From: Date: August 5 2008 12:53pm Subject: bzr commit into mysql-5.1-telco-6.4 tree (frazer:2697) Bug#37672 List-Archive: http://lists.mysql.com/commits/50916 X-Bug: 37672 Message-Id: <200808051053.m75ArJ8T029740@forth.ndb.mysql.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============2069302723==" --===============2069302723== 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.4/ ------------------------------------------------------------ revno: 2697 revision-id: frazer@stripped parent: msvensson@stripped parent: frazer@stripped committer: Frazer Clement branch nick: mysql-5.1-telco-6.4 timestamp: Tue 2008-08-05 11:52:53 +0100 message: Merge 6.3->6.4 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 ------------------------------------------------------------ revno: 2585.7.19 revision-id: frazer@stripped parent: msvensson@stripped parent: frazer@stripped committer: Frazer Clement branch nick: mysql-5.1-telco-6.3 timestamp: Tue 2008-08-05 11:13:56 +0100 message: Merge 6.2->6.3 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 ------------------------------------------------------------ revno: 2572.21.5 revision-id: frazer@stripped parent: msvensson@stripped committer: Frazer Clement branch nick: mysql-5.1-telco-6.2 timestamp: Mon 2008-08-04 16:49:01 +0100 message: Bug# 37672 NDBAPI : NdbRecord option OO_ANYVALUE causes interpreted delete to abort. NdbRecord variant of NDBAPI did not properly support ANYVALUE with Delete operations Additionally, DbTUP did not correctly support ANYVALUE with interpreted Delete operations. 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 --===============2069302723== MIME-Version: 1.0 Content-Type: text/text/x-diff; charset="us-ascii"; name="patch-2697.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-06-05 20:34:20 +0000 +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp 2008-08-05 10:52:53 +0000 @@ -1921,7 +1921,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)) { @@ -2027,7 +2031,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-17 20:28:45 +0000 +++ b/storage/ndb/src/ndbapi/NdbOperationExec.cpp 2008-08-05 10:52:53 +0000 @@ -942,6 +942,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) { @@ -1126,10 +1148,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-08-04 13:40:17 +0000 +++ b/storage/ndb/test/ndbapi/test_event.cpp 2008-08-05 10:52:53 +0000 @@ -23,14 +23,13 @@ #include #include -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(); @@ -87,6 +86,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]; @@ -2688,6 +2697,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" @@ -2879,6 +3228,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-07-01 15:01:50 +0000 +++ b/storage/ndb/test/run-test/daily-basic-tests.txt 2008-08-05 10:52:53 +0000 @@ -1197,6 +1197,11 @@ cmd: testBasic args: -n PkUpdate WIDE_MAXKEY_HUGO WIDE_MAXATTR_HUGO WIDE_MAXKEYMAXCOLS_HUGO WIDE_MINKEYMAXCOLS_HUGO - # EOF 2008-06-30 + +max-time: 500 +cmd: test_event +args -n bug37672 T1 + +#EOF 2008-07-04 # EOF --===============2069302723==--