List:Commits« Previous MessageNext Message »
From:Frazer Clement Date:November 8 2008 10:40pm
Subject:bzr push into mysql-5.1 branch (frazer:2736 to 2737)
View as plain text  
 2737 Frazer Clement	2008-11-08 [merge]
      Merge 6.2 -> 6.3
modified:
  mysql-test/suite/ndb/r/ndb_blob.result
  mysql-test/suite/ndb/t/ndb_blob.test
  sql/ha_ndbcluster.cc
  storage/ndb/include/ndbapi/NdbBlob.hpp
  storage/ndb/include/ndbapi/NdbOperation.hpp
  storage/ndb/include/ndbapi/NdbScanOperation.hpp
  storage/ndb/src/common/debugger/signaldata/SignalNames.cpp
  storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp
  storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
  storage/ndb/src/ndbapi/NdbBlob.cpp
  storage/ndb/src/ndbapi/NdbOperation.cpp
  storage/ndb/src/ndbapi/NdbOperationSearch.cpp
  storage/ndb/src/ndbapi/NdbScanOperation.cpp
  storage/ndb/test/ndbapi/testNdbApi.cpp
  storage/ndb/test/ndbapi/testOperations.cpp
  storage/ndb/test/ndbapi/testTransactions.cpp
  storage/ndb/test/run-test/daily-basic-tests.txt

 2736 Jonas Oreland	2008-11-07
      ndb - remove incorrect assertions
modified:
  storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp

=== modified file 'mysql-test/suite/ndb/r/ndb_blob.result'
--- a/mysql-test/suite/ndb/r/ndb_blob.result	2008-06-03 15:03:16 +0000
+++ b/mysql-test/suite/ndb/r/ndb_blob.result	2008-11-08 21:22:57 +0000
@@ -636,3 +636,16 @@ select (giga = repeat(@stuff, 2000)) fro
 (giga = repeat(@stuff, 2000))
 1
 drop table t1;
+create table t1 (
+id int, 
+data longblob, 
+primary key(id))
+engine=ndb;
+set @blurb= repeat('B', 1000000);
+set @blurbHash= sha1(@blurb);
+set autocommit = 1;
+insert into t1 values (1, @blurb);
+create table result_space (k int primary key, result int) engine=myisam;
+set autocommit = 0;
+drop table result_space;
+drop table t1;

=== modified file 'mysql-test/suite/ndb/t/ndb_blob.test'
--- a/mysql-test/suite/ndb/t/ndb_blob.test	2008-06-03 15:03:16 +0000
+++ b/mysql-test/suite/ndb/t/ndb_blob.test	2008-11-08 21:22:57 +0000
@@ -588,3 +588,114 @@ select sha1(giga) from t1;
 select (giga = repeat(@stuff, 2000)) from t1 where a=0;
 
 drop table t1;
+
+# bug# 39867 : Blob part operation error handling 
+# We attempt to generate a transporter overload
+# and check that an error is generated, rather than 
+# rubbish being silently returned.
+# Since transporter overload is not easy to reliably
+# reproduce, this testcase passes when all SELECTS
+# return either the correct result, or fail with
+# MySQL error 1297, and warnings about transporter
+# overload from Ndb. (1218)
+# The testcase will fail if there is no error, and 
+# incorrect data/NULL, or if there is an error other 
+# than 1297 due to 1218.
+#
+
+create table t1 (
+        id int, 
+        data longblob, 
+        primary key(id))
+        engine=ndb;
+
+set @blurb= repeat('B', 1000000); # ~1MB of stuff
+set @blurbHash= sha1(@blurb);
+
+set autocommit = 1;
+
+let $mysqltest_loopcounter= 500;
+let $success_count=0;
+let $fail_count=0;
+
+
+insert into t1 values (1, @blurb);
+
+create table result_space (k int primary key, result int) engine=myisam;
+
+--disable_result_log
+--disable_query_log
+
+while ($mysqltest_loopcounter)
+{
+  # Allow success or unmapped error type (1297).
+  --error 0,1297
+  insert into result_space select 1, (sha1(data) = @blurbHash) from t1 where id=1;  
+
+  let $orig_errno= $mysql_errno;
+
+  # Statement execution success path
+  if (!$orig_errno)
+  {
+    # Test that the SHA1 of the data read was as expected 
+    # (e.g. comparison returned true) 
+    let $is_right_answer=`SELECT result from result_space where k=1`;
+
+    if (!$is_right_answer)
+    {
+      --enable_result_log
+      echo SELECT succeeded but gave bad result.
+      SHOW WARNINGS;
+      die "Bad data returned";
+    }
+    #echo Success gave correct result;
+    inc $success_count;
+  }
+  
+  # Statement execution failure path
+  if ($orig_errno)
+  {
+    inc $fail_count;
+    #echo FAIL;
+
+    # For the error we are interested in (1218), MySQLD returns a generic error
+    # code (1297).  We use the warning info to check the Ndb error.
+    # Note that sometimes the end of the warning states 'from NDB', sometimes
+    # 'from NDBCLUSTER'.  Probably it should be made consistent.
+    #
+    let $warning_message= query_get_value("SHOW WARNINGS", Message, 1);
+    let $is_correct_message= `SELECT "$warning_message" LIKE "Got temporary error 1218 'Send Buffers overloaded in NDB kernel' from NDB%"`;
+
+    if (!$is_correct_message)
+    {
+      --enable_result_log
+      echo SELECT failed with incorrect error ($mysql_errno);
+      SHOW WARNINGS;
+      die "Incorrect error from statement";
+    }
+    #echo Failed as expected;
+  }
+
+  delete from result_space;
+
+  #echo $mysqltest_loopcounter;
+  
+  dec $mysqltest_loopcounter;
+
+  if ($fail_count = 20)
+  {
+    # That's enough punishment
+    #echo Exiting loop early at iteration $mysqltest_loopcounter;
+    let $mysqltest_loopcounter= 0;
+  }
+}
+
+--enable_result_log
+--enable_query_log
+
+# Interesting, but can't output as it's different every time
+# echo Successes $success_count;
+# echo Failures $fail_count;
+set autocommit = 0;
+drop table result_space;
+drop table t1;

=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc	2008-10-29 13:22:19 +0000
+++ b/sql/ha_ndbcluster.cc	2008-11-08 21:22:57 +0000
@@ -921,6 +921,33 @@ ha_ndbcluster::copy_row_to_buffer(Thd_nd
   return row;
 }
 
+/**
+ * findBlobError
+ * This method attempts to find an error in the hierarchy of runtime
+ * NDBAPI objects from Blob up to transaction.
+ * It will return -1 if no error is found, 0 if an error is found.
+ */
+int findBlobError(NdbError& error, NdbBlob* pBlob)
+{
+  error= pBlob->getNdbError();
+  if (error.code != 0)
+    return 0;
+  
+  const NdbOperation* pOp= pBlob->getNdbOperation();
+  error= pOp->getNdbError();
+  if (error.code != 0)
+    return 0;
+  
+  NdbTransaction* pTrans= pOp->getNdbTransaction();
+  error= pTrans->getNdbError();
+  if (error.code != 0)
+    return 0;
+  
+  /* No error on any of the objects */
+  return -1;
+}
+
+
 int g_get_ndb_blobs_value(NdbBlob *ndb_blob, void *arg)
 {
   ha_ndbcluster *ha= (ha_ndbcluster *)arg;
@@ -999,7 +1026,19 @@ int g_get_ndb_blobs_value(NdbBlob *ndb_b
       uchar *buf= ha->m_blobs_buffer + offset;
       uint32 len= ha->m_blobs_buffer_size - offset;
       if (ndb_blob->readData(buf, len) != 0)
-          ERR_RETURN(ndb_blob->getNdbError());
+      {
+        NdbError err;
+        if (findBlobError(err, ndb_blob) == 0)
+        {
+          ERR_RETURN(err);
+        }
+        else
+        {
+          /* Should always have some error code set */
+          assert(err.code != 0);
+          ERR_RETURN(err);
+        }
+      }   
       DBUG_PRINT("info", ("[%u] offset: %u  buf: 0x%lx  len=%u",
                           i, offset, (long) buf, len));
       DBUG_ASSERT(len == len64);

=== modified file 'storage/ndb/include/ndbapi/NdbBlob.hpp'
--- a/storage/ndb/include/ndbapi/NdbBlob.hpp	2008-02-19 10:41:22 +0000
+++ b/storage/ndb/include/ndbapi/NdbBlob.hpp	2008-11-08 20:40:15 +0000
@@ -263,6 +263,13 @@ public:
    */
   const NdbError& getNdbError() const;
   /**
+   * Get a pointer to the operation which this Blob Handle
+   * was initially created as part of.
+   * Note that this could be a scan operation.
+   * Note that the pointer returned is a const pointer.
+   */
+  const NdbOperation* getNdbOperation() const;  
+  /**
    * Return info about all blobs in this operation.
    *
    * Get first blob in list.

=== modified file 'storage/ndb/include/ndbapi/NdbOperation.hpp'
--- a/storage/ndb/include/ndbapi/NdbOperation.hpp	2008-08-07 11:51:34 +0000
+++ b/storage/ndb/include/ndbapi/NdbOperation.hpp	2008-11-08 21:22:57 +0000
@@ -838,6 +838,7 @@ public:
    * @return method number where the error occured.
    */
   int getNdbErrorLine();
+  int getNdbErrorLine() const;
 
   /**
    * Get table name of this operation.
@@ -886,6 +887,11 @@ public:
    */
   AbortOption getAbortOption() const;
   int setAbortOption(AbortOption);
+
+  /**
+   * Get NdbTransaction object pointer for this operation
+   */
+  virtual NdbTransaction* getNdbTransaction() const;
   
 #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
   
@@ -1042,7 +1048,6 @@ protected:
 
 public:
 #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
-  NdbTransaction* getNdbTransaction();
   const NdbOperation* next() const;
   const NdbRecAttr* getFirstRecAttr() const;
 
@@ -1483,6 +1488,13 @@ NdbOperation::getNdbErrorLine()
   return theErrorLine;
 }
 
+inline
+int
+NdbOperation::getNdbErrorLine() const
+{
+  return theErrorLine;
+}
+
 /******************************************************************************
 void next(NdbOperation* aNdbOperation);
 

=== modified file 'storage/ndb/include/ndbapi/NdbScanOperation.hpp'
--- a/storage/ndb/include/ndbapi/NdbScanOperation.hpp	2008-08-11 12:46:21 +0000
+++ b/storage/ndb/include/ndbapi/NdbScanOperation.hpp	2008-11-08 21:22:57 +0000
@@ -377,6 +377,11 @@ public:
                                          const NdbOperation::OperationOptions *opts = 0,
                                          Uint32 sizeOfOptions = 0);
 
+  /**
+   * Get NdbTransaction object for this scan operation
+   */
+  NdbTransaction* getNdbTransaction() const;
+
 protected:
   NdbScanOperation(Ndb* aNdb,
                    NdbOperation::Type aType = NdbOperation::TableScan);
@@ -657,4 +662,14 @@ NdbScanOperation::deleteCurrentTuple(Ndb
                                  opts, sizeOfOptions);
 }
 
+inline
+NdbTransaction*
+NdbScanOperation::getNdbTransaction() const
+{
+  /* return the user visible transaction object ptr, not the
+   * scan's 'internal' / buddy transaction object
+   */
+  return m_transConnection;
+};
+
 #endif

=== modified file 'storage/ndb/src/common/debugger/signaldata/SignalNames.cpp'
--- a/storage/ndb/src/common/debugger/signaldata/SignalNames.cpp	2007-11-23 07:15:16 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/SignalNames.cpp	2008-11-08 21:22:57 +0000
@@ -647,6 +647,8 @@ const GsnName SignalNames [] = {
 
   ,{ GSN_UPGRADE_PROTOCOL_ORD, "UPGRADE_PROTOCOL_ORD" }
 
+  ,{ GSN_TC_HBREP, "TC_HBREP" }
+  
   ,{ GSN_START_TOREF, "START_TOREF" }
   ,{ GSN_END_TOREF, "END_TOREF" }
   ,{ GSN_START_PERMREP, "START_PERMREP" }

=== modified file 'storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp'
--- a/storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp	2008-08-27 20:10:42 +0000
+++ b/storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp	2008-11-08 21:22:57 +0000
@@ -212,6 +212,15 @@ void Cmvmi::execEVENT_REP(Signal* signal
   if (nodeId == 0)
   {
     nodeId= refToNode(signal->getSendersBlockRef());
+
+    if (nodeId == 0)
+    {
+      /* Event reporter supplied no node id,
+       * assume it was local
+       */
+      nodeId= getOwnNodeId();
+    }
+
     eventReport->setNodeId(nodeId);
   }
 

=== modified file 'storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp	2008-11-07 10:33:31 +0000
+++ b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp	2008-11-08 21:22:57 +0000
@@ -2285,9 +2285,10 @@ void Dblqh::noFreeRecordLab(Signal* sign
     releaseTcrec(signal, tcConnectptr);
   }
 
-  if (LqhKeyReq::getSimpleFlag(reqInfo) && 
+  if (LqhKeyReq::getDirtyFlag(reqInfo) && 
       LqhKeyReq::getOperation(reqInfo) == ZREAD){ 
     jam();
+    /* Dirty read sends TCKEYREF direct to client, and nothing to TC */
     ndbrequire(LqhKeyReq::getApplicationAddressFlag(reqInfo));
     const Uint32 apiRef   = lqhKeyReq->variableData[0];
     const Uint32 apiOpRec = lqhKeyReq->variableData[1];
@@ -2301,6 +2302,9 @@ void Dblqh::noFreeRecordLab(Signal* sign
     sendTCKEYREF(signal, apiRef, signal->getSendersBlockRef(), 0);
   } else {
     jam();
+    /* All ops apart from dirty read send LQHKEYREF to TC
+     * (This includes simple read)
+     */
 
     const Uint32 clientPtr = lqhKeyReq->clientConnectPtr;
     Uint32 TcOprec = clientPtr;

=== modified file 'storage/ndb/src/ndbapi/NdbBlob.cpp'
--- a/storage/ndb/src/ndbapi/NdbBlob.cpp	2008-06-03 10:00:31 +0000
+++ b/storage/ndb/src/ndbapi/NdbBlob.cpp	2008-11-08 20:40:15 +0000
@@ -3070,3 +3070,8 @@ NdbBlob::blobsNextBlob()
   return theNext;
 }
 
+const NdbOperation*
+NdbBlob::getNdbOperation() const
+{
+  return theNdbOp;
+};

=== modified file 'storage/ndb/src/ndbapi/NdbOperation.cpp'
--- a/storage/ndb/src/ndbapi/NdbOperation.cpp	2008-04-29 13:03:02 +0000
+++ b/storage/ndb/src/ndbapi/NdbOperation.cpp	2008-11-08 21:22:57 +0000
@@ -519,7 +519,7 @@ NdbOperation::getTable() const
 }
 
 NdbTransaction* 
-NdbOperation::getNdbTransaction()
+NdbOperation::getNdbTransaction() const
 {
   return theNdbCon; 
 }

=== modified file 'storage/ndb/src/ndbapi/NdbOperationSearch.cpp'
--- a/storage/ndb/src/ndbapi/NdbOperationSearch.cpp	2008-06-03 10:00:31 +0000
+++ b/storage/ndb/src/ndbapi/NdbOperationSearch.cpp	2008-11-08 21:06:51 +0000
@@ -58,7 +58,9 @@ NdbOperation::equal_impl(const NdbColumn
 {
   DBUG_ENTER("NdbOperation::equal_impl");
   DBUG_PRINT("enter", ("col: %s  op: %d  val: 0x%lx",
-                       tAttrInfo->m_name.c_str(), theOperationType,
+                       (tAttrInfo == NULL) ? "NULL" :
+                       tAttrInfo->m_name.c_str(), 
+                       theOperationType,
                        (long) aValuePassed));
   
   const char* aValue = aValuePassed;

=== modified file 'storage/ndb/src/ndbapi/NdbScanOperation.cpp'
--- a/storage/ndb/src/ndbapi/NdbScanOperation.cpp	2008-11-06 16:51:50 +0000
+++ b/storage/ndb/src/ndbapi/NdbScanOperation.cpp	2008-11-08 21:22:57 +0000
@@ -2362,31 +2362,49 @@ NdbScanOperation::takeOverScanOpNdbRecor
 NdbBlob*
 NdbScanOperation::getBlobHandle(const char* anAttrName)
 {
-  /* We need the row KeyInfo for Blobs
-   * Old Api scans have saved flags at this point
-   */
-  if (m_scanUsingOldApi)
-    m_savedScanFlagsOldApi|= SF_KeyInfo;
+  const NdbColumnImpl* col= m_currentTable->getColumn(anAttrName);
+  
+  if (col != NULL)
+  {
+    /* We need the row KeyInfo for Blobs
+     * Old Api scans have saved flags at this point
+     */
+    if (m_scanUsingOldApi)
+      m_savedScanFlagsOldApi|= SF_KeyInfo;
+    else
+      m_keyInfo= 1;
+    
+    return NdbOperation::getBlobHandle(m_transConnection, col);
+  }
   else
-    m_keyInfo= 1;
-
-  return NdbOperation::getBlobHandle(m_transConnection, 
-                                     m_currentTable->getColumn(anAttrName));
+  {
+    setErrorCode(4004);
+    return NULL;
+  }
 }
 
 NdbBlob*
 NdbScanOperation::getBlobHandle(Uint32 anAttrId)
 {
-  /* We need the row KeyInfo for Blobs 
-   * Old Api scans have saved flags at this point
-   */
-  if (m_scanUsingOldApi)
-    m_savedScanFlagsOldApi|= SF_KeyInfo;
+  const NdbColumnImpl* col= m_currentTable->getColumn(anAttrId);
+  
+  if (col != NULL)
+  {
+    /* We need the row KeyInfo for Blobs 
+     * Old Api scans have saved flags at this point
+     */
+    if (m_scanUsingOldApi)
+      m_savedScanFlagsOldApi|= SF_KeyInfo;
+    else
+      m_keyInfo= 1;
+    
+    return NdbOperation::getBlobHandle(m_transConnection, col);
+  }
   else
-    m_keyInfo= 1;
-
-  return NdbOperation::getBlobHandle(m_transConnection, 
-                                     m_currentTable->getColumn(anAttrId));
+  {
+    setErrorCode(4004);
+    return NULL;
+  }
 }
 
 /** 

=== modified file 'storage/ndb/test/ndbapi/testNdbApi.cpp'
--- a/storage/ndb/test/ndbapi/testNdbApi.cpp	2008-06-03 12:37:17 +0000
+++ b/storage/ndb/test/ndbapi/testNdbApi.cpp	2008-11-08 21:06:51 +0000
@@ -26,10 +26,8 @@
 #define MAX_NDB_OBJECTS 32678
 
 #define CHECK(b) if (!(b)) { \
-  ndbout << "ERR: "<< step->getName() \
-         << " failed on line " << __LINE__ << endl; \
-  result = NDBT_FAILED; \
-  continue; } 
+  ndbout << "ERR: failed on line " << __LINE__ << endl; \
+  return -1; } 
 
 #define CHECKE(b) if (!(b)) { \
   errors++; \
@@ -628,6 +626,175 @@ int runGetNdbOperationNoTab(NDBT_Context
   return NDBT_OK;
 }
 
+int runBadColNameHandling(NDBT_Context* ctx, NDBT_Step* step){
+  int result = NDBT_OK;
+  const NdbDictionary::Table* pTab = ctx->getTab();
+
+
+  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;
+  }
+  
+  const int CASES= 5;
+  int i;
+
+  for (i= 0; i < CASES; i++)
+  {
+    ndbout << "Case " << i << endl;
+    NdbConnection* pCon = pNdb->startTransaction();
+    if (pCon == NULL){
+      pNdb->closeTransaction(pCon);  
+      delete pNdb;
+      return NDBT_FAILED;
+    }
+    
+    /* Cases 0-3 use PK ops, 4 + use scans */ 
+    NdbOperation* pOp = (i < 4 ? pCon->getNdbOperation(pTab->getName()):
+                         pCon->getNdbScanOperation(pTab->getName()));
+    if (pOp == NULL){
+      ERR(pCon->getNdbError());
+      pNdb->closeTransaction(pCon);  
+      delete pNdb;
+      return NDBT_FAILED;
+    }
+
+    bool failed= false;
+    int expectedError= 0;
+    HugoOperations hugoOps(*pTab);
+
+    switch(i) {
+    case 0:
+      if (pOp->readTuple() != 0){
+        ERR(pCon->getNdbError());
+        pNdb->closeTransaction(pCon);
+        delete pNdb;
+        return NDBT_FAILED;
+      }
+      
+      // getValue should fail, we check that we get correct errors
+      // in expected places.
+      expectedError= 4004;
+      failed= (pOp->getValue("MOST_IMPROBABLE2") == NULL);
+      break;
+
+    case 1:
+      if (pOp->readTuple() != 0){
+        ERR(pCon->getNdbError());
+        pNdb->closeTransaction(pCon);
+        delete pNdb;
+        return NDBT_FAILED;
+      }
+      
+      // equal should fail, we check that we get correct errors
+      // in expected places.
+      expectedError= 4004;
+      failed= (pOp->equal("MOST_IMPROBABLE2", 0) != 0);
+      break;
+
+    case 2:
+      if (pOp->writeTuple() != 0){
+        ERR(pCon->getNdbError());
+        pNdb->closeTransaction(pCon);
+        delete pNdb;
+        return NDBT_FAILED;
+      }
+
+      // set equality on pk columns
+      for(int a = 0; a<pTab->getNoOfColumns(); a++){
+        if (pTab->getColumn(a)->getPrimaryKey() == true){
+          if(hugoOps.equalForAttr(pOp, a, 1) != 0){
+            const NdbError err = pCon->getNdbError();
+            ERR(err);
+            pNdb->closeTransaction(pCon);
+            delete pNdb;
+            return NDBT_FAILED;
+          }
+        }
+      }
+      
+      // setValue should fail, we check that we get correct errors
+      // in expected places.
+      expectedError= 4004;
+      failed= (pOp->setValue("MOST_IMPROBABLE2", 0) != 0);
+      break;
+
+    case 3:
+      if (pOp->readTuple() != 0){
+        ERR(pCon->getNdbError());
+        pNdb->closeTransaction(pCon);
+        delete pNdb;
+        return NDBT_FAILED;
+      }
+      
+      // getBlobHandle should fail, we check that we get correct errors
+      // in expected places.
+      expectedError= 4004;
+      failed= (pOp->getBlobHandle("MOST_IMPROBABLE2") == NULL);
+      break;
+
+    case 4:
+    {
+      NdbScanOperation* sop= (NdbScanOperation*) pOp;
+      if (sop->readTuples() != 0){
+        ERR(pCon->getNdbError());
+        pNdb->closeTransaction(pCon);
+        delete pNdb;
+        return NDBT_FAILED;
+      }
+      
+      // getBlobHandle should fail, we check that we get correct errors
+      // in expected places.
+      expectedError= 4004;
+      ndbout << "About to call getBlobHandle" << endl;
+      failed= (sop->getBlobHandle("MOST_IMPROBABLE2") == NULL);
+
+      sop->close();
+      break;
+    } 
+    
+    default:
+      break;
+    }
+
+    if (failed)
+    {
+      const NdbError opErr= pOp->getNdbError();
+      const NdbError transErr = pCon->getNdbError();
+      ERR(opErr);
+      ERR(transErr);
+      if (opErr.code != transErr.code) {
+        ndbout << "Error reporting mismatch, expected " 
+               << expectedError << endl;
+        result = NDBT_FAILED;
+      }
+      if (opErr.code != expectedError){
+        ndbout << "No or bad error detected, expected " 
+               << expectedError << endl;
+        result = NDBT_FAILED;	
+      }
+    } else {
+      ndbout << "Case " << i << " did not fail" << endl;
+      result = NDBT_FAILED;
+    }
+
+    pNdb->closeTransaction(pCon);
+
+    if (result == NDBT_FAILED)
+      break;
+  } // for
+  
+  delete pNdb;
+
+  return result;
+}
+
 int runMissingOperation(NDBT_Context* ctx, NDBT_Step* step){
   int result = NDBT_OK;
   const NdbDictionary::Table* pTab = ctx->getTab();
@@ -1326,6 +1493,7 @@ op_row(NdbTransaction* pTrans, HugoOpera
   case 3:
   case 4:
   case 5:
+  case 12:
     pOp = pTrans->getNdbOperation(pTab->getName());
     break;
   case 9:
@@ -1365,10 +1533,13 @@ op_row(NdbTransaction* pTrans, HugoOpera
   case 11:
     pOp->deleteTuple();
     break;
+  case 12:
+    CHECK(!pOp->simpleRead());
+    break;
   default:
     abort();
   }
-  
+
   for(int a = 0; a<pTab->getNoOfColumns(); a++){
     if (pTab->getColumn(a)->getPrimaryKey() == true){
       if(hugoOps.equalForAttr(pOp, a, row) != 0){
@@ -1384,8 +1555,9 @@ op_row(NdbTransaction* pTrans, HugoOpera
   case 6:
   case 7:
   case 8:
+  case 12:
     for(int a = 0; a<pTab->getNoOfColumns(); a++){
-      pOp->getValue(a);
+      CHECK(pOp->getValue(a));
     }
     break;
   case 3: 
@@ -1427,6 +1599,8 @@ static void print(int op)
   case 9:  str = "noop      "; break;
   case 10: str = "uk update "; break;
   case 11: str = "uk delete "; break;
+  case 12: str = "pk read-si"; break;
+
   default:
     abort();
   }
@@ -1457,9 +1631,10 @@ runTestIgnoreError(NDBT_Context* ctx, ND
 
   printf("case: <op1>     <op2>       c/nc ao/ie\n");
   Uint32 tno = 0;
-  for (Uint32 op1 = 0; op1 < 12; op1++)
+  for (Uint32 op1 = 0; op1 < 13; op1++)
   {
-    for (Uint32 op2 = op1; op2 < 12; op2++)
+    // NOTE : I get a node crash if the following loop starts from 0!
+    for (Uint32 op2 = op1; op2 < 13; op2++)
     {
       int ret;
       NdbTransaction* pTrans = 0;
@@ -1486,25 +1661,25 @@ runTestIgnoreError(NDBT_Context* ctx, ND
 	
 
 	hugoTrans.loadTable(pNdb, 1);
-	pTrans = pNdb->startTransaction();
-	op_row(pTrans, hugoOps, pTab, op1, 0);
+	CHECK(pTrans = pNdb->startTransaction());
+	CHECK(!op_row(pTrans, hugoOps, pTab, op1, 0));
 	ret = pTrans->execute(et, ao);
 	pTrans->close();
 	printf("%d ", ret);
 	hugoTrans.clearTable(pNdb);
 
 	hugoTrans.loadTable(pNdb, 1);
-	pTrans = pNdb->startTransaction();
-	op_row(pTrans, hugoOps, pTab, op1, 1);
+	CHECK(pTrans = pNdb->startTransaction());
+	CHECK(!op_row(pTrans, hugoOps, pTab, op1, 1));
 	ret = pTrans->execute(et, ao);
 	pTrans->close();
 	printf("%d ", ret);
 	hugoTrans.clearTable(pNdb);
       
 	hugoTrans.loadTable(pNdb, 1);
-	pTrans = pNdb->startTransaction();
-	op_row(pTrans, hugoOps, pTab, op1, 0);
-	op_row(pTrans, hugoOps, pTab, op2, 1);
+	CHECK(pTrans = pNdb->startTransaction());
+	CHECK(!op_row(pTrans, hugoOps, pTab, op1, 0));
+	CHECK(!op_row(pTrans, hugoOps, pTab, op2, 1));
 	ret = pTrans->execute(et, ao);
 	pTrans->close();
 	printf("%d\n", ret);
@@ -1728,6 +1903,85 @@ done:
   return result;
 }
 
+int
+simpleReadAbortOnError(NDBT_Context* ctx, NDBT_Step* step)
+{
+  /* Simple read has some error handling issues
+   * Setting the operation to be AbortOnError can expose these
+   */
+  Ndb* pNdb = GETNDB(step);
+  const NdbDictionary::Table* pTab= ctx->getTab();
+  HugoOperations hugoOps(*pTab);
+  NdbRestarter restarter;
+
+  hugoOps.startTransaction(pNdb);
+  CHECK(!hugoOps.pkWriteRecord(pNdb,0));
+  CHECK(!hugoOps.execute_Commit(pNdb, AbortOnError));
+
+  NdbTransaction* trans;
+  
+  CHECK(trans= pNdb->startTransaction());
+
+  /* Insert error 5047 which causes next LQHKEYREQ to fail due
+   * to 'transporter overload'
+   * Error insert is self-clearing
+   */
+  restarter.insertErrorInAllNodes(5047);
+
+  /* Create SimpleRead on row 0, which exists (though we'll get
+   * 'transporter overload for this'
+   */
+  NdbOperation* op;
+  CHECK(op= trans->getNdbOperation(pTab));
+
+  CHECK(!op->simpleRead());
+
+  for(int a = 0; a<pTab->getNoOfColumns(); a++){
+    if (pTab->getColumn(a)->getPrimaryKey() == true){
+      if(hugoOps.equalForAttr(op, a, 0) != 0){
+        restarter.insertErrorInAllNodes(0);  
+	return NDBT_FAILED;
+      }
+    }
+  }
+  for(int a = 0; a<pTab->getNoOfColumns(); a++){
+    CHECK(op->getValue(a));
+  }
+  
+  CHECK(!op->setAbortOption(NdbOperation::AbortOnError));
+
+  /* Create normal read on row 0 which will succeed */
+  NdbOperation* op2;
+  CHECK(op2= trans->getNdbOperation(pTab));
+
+  CHECK(!op2->readTuple());
+
+  for(int a = 0; a<pTab->getNoOfColumns(); a++){
+    if (pTab->getColumn(a)->getPrimaryKey() == true){
+      if(hugoOps.equalForAttr(op2, a, 0) != 0){
+        restarter.insertErrorInAllNodes(0);  
+	return NDBT_FAILED;
+      }
+    }
+  }
+  for(int a = 0; a<pTab->getNoOfColumns(); a++){
+    CHECK(op2->getValue(a));
+  }
+  
+  CHECK(!op2->setAbortOption(NdbOperation::AbortOnError));
+
+
+  CHECK(trans->execute(NoCommit) == -1);
+
+  CHECK(trans->getNdbError().code == 1218); // Transporter Overload
+
+  restarter.insertErrorInAllNodes(0);  
+
+  return NDBT_OK;
+  
+}
+
+
 NDBT_TESTSUITE(testNdbApi);
 TESTCASE("MaxNdb", 
 	 "Create Ndb objects until no more can be created\n"){ 
@@ -1769,6 +2023,10 @@ TESTCASE("GetOperationNoTab", 
 	"Call getNdbOperation on a table that does not exist\n"){ 
   INITIALIZER(runGetNdbOperationNoTab);
 }
+TESTCASE("BadColNameHandling",
+         "Call methods with an invalid column name and check error handling\n"){
+  INITIALIZER(runBadColNameHandling);
+}
 TESTCASE("MissingOperation", 
 	"Missing operation request(insertTuple) should give an error code\n"){ 
   INITIALIZER(runMissingOperation);
@@ -1840,6 +2098,10 @@ TESTCASE("Bug37158", 
 	 ""){ 
   INITIALIZER(runBug37158);
 }
+TESTCASE("SimpleReadAbortOnError",
+         "Test behaviour of Simple reads with Abort On Error"){
+  INITIALIZER(simpleReadAbortOnError);
+}
 NDBT_TESTSUITE_END(testNdbApi);
 
 int main(int argc, const char** argv){

=== modified file 'storage/ndb/test/ndbapi/testOperations.cpp'
--- a/storage/ndb/test/ndbapi/testOperations.cpp	2007-08-01 03:07:58 +0000
+++ b/storage/ndb/test/ndbapi/testOperations.cpp	2008-11-08 20:45:48 +0000
@@ -59,6 +59,20 @@ OperationTestCase matrix[] = {
   { "FReadUpdate",     false, "READ", 626, 0, "UPDATE",  626, 0, 626, 0 },
   { "FReadDelete",     false, "READ", 626, 0, "DELETE",  626, 0, 626, 0 },
 
+  { "FSimpleReadRead", false, "S-READ", 626, 0, "READ",    626, 0, 626, 0 },
+  { "FSimpleReadReadEx", 
+                       false, "S-READ", 626, 0, "READ-EX", 626, 0, 626, 0 },
+  { "FSimpleReadSimpleRead",
+                       false, "S-READ", 626, 0, "S-READ",  626, 0, 626, 0 },
+  { "FSimpleReadDirtyRead",
+                       false, "S-READ", 626, 0, "D-READ",  626, 0, 626, 0 },
+  { "FSimpleReadInsert",  
+                       false, "S-READ", 626, 0, "INSERT",    0, 1,   0, 1 },
+  { "FSimpleReadUpdate",
+                       false, "S-READ", 626, 0, "UPDATE",  626, 0, 626, 0 },
+  { "FSimpleReadDelete",
+                       false, "S-READ", 626, 0, "DELETE",  626, 0, 626, 0 },
+
   { "ReadExRead",       true, "READ-EX", 0, 0, "READ",      0, 0,   0, 0 },
   { "ReadExReadEx",     true, "READ-EX", 0, 0, "READ-EX",   0, 0,   0, 0 },
   { "ReadExSimpleRead", true, "READ-EX", 0, 0, "S-READ",    0, 0,   0, 0 },
@@ -118,7 +132,7 @@ runOp(HugoOperations & hugoOps,
   } else if(strcmp(op, "READ-EX") == 0){
     C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive), 0);      
   } else if(strcmp(op, "S-READ") == 0){
-    C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Read), 0);
+    C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_SimpleRead), 0);
   } else if(strcmp(op, "D-READ") == 0){
     C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_CommittedRead), 0);
   } else if(strcmp(op, "INSERT") == 0){

=== modified file 'storage/ndb/test/ndbapi/testTransactions.cpp'
--- a/storage/ndb/test/ndbapi/testTransactions.cpp	2006-12-23 19:20:40 +0000
+++ b/storage/ndb/test/ndbapi/testTransactions.cpp	2008-11-08 20:45:48 +0000
@@ -109,6 +109,23 @@ OperationTestCase matrix[] = {
   { "ScanExScanDe",     true, "SCAN-EX",1, "SCAN-DE", 266, X,   0, 1 },
 #endif
 
+  { "SimpleReadRead",   true, "S-READ", 1, "READ",      0, 1,   0, 1 },
+  { "SimpleReadReadEx", true, "S-READ", 1, "READ-EX",   0, 1,   0, 1 }, // no lock held
+  { "SimpleReadSimpleRead",
+                        true, "S-READ", 1, "S-READ",    0, 1,   0, 1 },
+  { "SimpleReadDirtyRead",
+                        true, "S-READ", 1, "D-READ",    0, 1,   0, 1 },
+  { "SimpleReadInsert", true, "S-READ", 1, "INSERT",  630, X,   0, 1 }, // no lock held
+  { "SimpleReadUpdate", true, "S-READ", 1, "UPDATE",    0, 2,   0, 2 }, // no lock held
+  { "SimpleReadDelete", true, "S-READ", 1, "DELETE",    0, X, 626, X }, // no lock held
+  { "SimpleReadScan",   true, "S-READ", 1, "SCAN",      0, 1,   0, 1 },
+  { "SimpleReadScanHl", true, "S-READ", 1, "SCAN-HL",   0, 1,   0, 1 },
+  { "SimpleReadScanEx", true, "S-READ", 1, "SCAN-EX",   0, 1,   0, 1 }, // no lock held
+#if 0
+  { "SimpleReadScanUp", true, "S-READ", 1, "SCAN-UP",   0, 1,   0, 2 }, // no lock held
+  { "SimpleReadScanDe", true, "S-READ", 1, "SCAN-DE",   0, X, 626, X }, // no lock held
+#endif
+
   { "ReadExRead",       true, "READ-EX",1, "READ",    266, X,   0, 1 },
   { "ReadExReadEx",     true, "READ-EX",1, "READ-EX", 266, X,   0, 1 },
   { "ReadExSimpleRead", true, "READ-EX",1, "S-READ",  266, X,   0, 1 },
@@ -169,6 +186,9 @@ OperationTestCase matrix[] = {
   { "DeleteScanDe",     true, "DELETE", X, "SCAN-DE", 266, X, 626, X }
 #endif
 
+
+
+
 };
 
 #define CHECK(a, b) { int x = a; int y = b; if (x != y) { \
@@ -193,7 +213,7 @@ runOp(HugoOperations & hugoOps,
   } else if(strcmp(op, "READ-EX") == 0){
     C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0);  
   } else if(strcmp(op, "S-READ") == 0){
-    C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Read) == 0);      
+    C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_SimpleRead) == 0);      
   } else if(strcmp(op, "D-READ") == 0){
     C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_CommittedRead) == 0); 
   } else if(strcmp(op, "INSERT") == 0){

=== modified file 'storage/ndb/test/run-test/daily-basic-tests.txt'
--- a/storage/ndb/test/run-test/daily-basic-tests.txt	2008-08-11 11:24:12 +0000
+++ b/storage/ndb/test/run-test/daily-basic-tests.txt	2008-11-08 21:22:57 +0000
@@ -765,6 +765,14 @@ cmd: testNdbApi
 args: -n Bug28443
 
 max-time: 500
+cmd: testNdbApi
+args: -n BadColNameHandling T6
+
+max-time: 500
+cmd: testNdbApi
+args: -n SimpleReadAbortOnError T1 T6 T15
+
+max-time: 500
 cmd: testInterpreter
 args: T1 
 
@@ -1183,3 +1191,4 @@ cmd: test_event
 args -r 5000 -n Bug30780 T1
 
 #EOF 2008-08-11
+

Thread
bzr push into mysql-5.1 branch (frazer:2736 to 2737) Frazer Clement8 Nov