=== 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 <NdbRestarts.hpp>
 #include <signaldata/DumpStateOrd.hpp>
 
-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


