=== modified file 'storage/ndb/include/kernel/signaldata/TcKeyRef.hpp'
--- a/storage/ndb/include/kernel/signaldata/TcKeyRef.hpp	2007-12-07 09:46:12 +0000
+++ b/storage/ndb/include/kernel/signaldata/TcKeyRef.hpp	2008-07-01 12:35:34 +0000
@@ -43,7 +43,7 @@
   STATIC_CONST( SignalLength = 5 );
 
 private:
-  Uint32 connectPtr;
+  Uint32 connectPtr; /* Operation pointer */
   Uint32 transId[2];
   Uint32 errorCode;
   Uint32 errorData;

=== modified file 'storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp'
--- a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp	2008-06-06 08:30:09 +0000
+++ b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp	2008-07-01 12:35:34 +0000
@@ -4367,6 +4367,7 @@
      * Release table
      */
     releaseTableObject(tablePtr.i, checkExist);
+    parseP->tablePtr.setNull();
     return;
   }
 

=== modified file 'storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp'
--- a/storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp	2008-06-17 20:28:45 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp	2008-07-01 12:35:34 +0000
@@ -1957,6 +1957,9 @@
   bool validate_filter(Signal*);
   bool match_and_print(Signal*, ApiConnectRecordPtr);
 
+  // For Error inserts
+  Uint32 errorInsertHoardedSegments;
+
   /************************** API CONNECT RECORD ***********************/
   /* *******************************************************************/
   /* THE API CONNECT RECORD CONTAINS THE CONNECTION RECORD TO WHICH THE*/

=== modified file 'storage/ndb/src/kernel/blocks/dbtc/DbtcInit.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtc/DbtcInit.cpp	2008-06-17 20:28:45 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtc/DbtcInit.cpp	2008-07-01 12:35:34 +0000
@@ -322,6 +322,8 @@
   tcFailRecord = 0;
   c_apiConTimer = 0;
   c_apiConTimer_line = 0;
+
+  errorInsertHoardedSegments= RNIL;
 }//Dbtc::Dbtc()
 
 Dbtc::~Dbtc() 

=== modified file 'storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp	2008-06-17 22:23:24 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp	2008-07-01 12:35:34 +0000
@@ -2165,6 +2165,12 @@
     int TattrlengthRemain = regCachePtr->attrlength - 
       regCachePtr->currReclenAi;
     
+    /* Setup tcConnectptr to ensure that error handling etc.
+     * can access required state
+     */
+    tcConnectptr.i = regApiPtr->lastTcConnect;
+    ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
+
     /* Add AttrInfo to any existing AttrInfo we have 
      * Some short TCKEYREQ signals have no ATTRINFO in
      * the TCKEYREQ itself
@@ -2174,7 +2180,7 @@
                           Tlength))
     {
       DEBUG("No more section segments available");
-      TCKEY_abort(signal, 24);
+      appendToSectionErrorLab(signal);
       return;
     }//if
 
@@ -2188,7 +2194,6 @@
       /* RECEIVED THEN IT IS NOT ALLOWED TO RECEIVE ANY FURTHER          */
       /* OPERATIONS.                                                     */
       /****************************************************************>*/
-      UintR TlastConnect = regApiPtr->lastTcConnect;
       if (TcompRECEIVING) {
         jam();
         regApiPtr->apiConnectstate = CS_STARTED;
@@ -2196,8 +2201,6 @@
         jam();
         regApiPtr->apiConnectstate = CS_START_COMMITTING;
       }//if
-      tcConnectptr.i = TlastConnect;
-      ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
       attrinfoDihReceivedLab(signal);
     } else if (TattrlengthRemain < 0) {
       jam();
@@ -2781,6 +2784,45 @@
   UintR TapiConnectptrIndex = apiConnectptr.i;
   UintR TsenderData = tcKeyReq->senderData;
 
+  if (ERROR_INSERTED(8065) || 
+      ERROR_INSERTED(8066) ||
+      ERROR_INSERTED(8067))
+  {
+    /* Consume all but 10(8065) or all but 1 (8066) or all (8077) of 
+     * the SegmentedSection buffers to allow testing of what happens 
+     * when they're exhausted, either in this signal or one to follow
+     * 8068 frees all 'hoarded' segments
+     */
+    Uint32 segmentsToLeave= ERROR_INSERTED(8065)? 
+      10 : 
+      ERROR_INSERTED(8066) ? 
+      1 :
+      0;
+    Uint32 freeSegments= g_sectionSegmentPool.getNoOfFree();
+    DEBUG("Hoarding all but " << segmentsToLeave << 
+          " of " << freeSegments << " free segments");
+    if (freeSegments >= segmentsToLeave)
+    {
+      Uint32 numToAlloc= (g_sectionSegmentPool.getNoOfFree() - segmentsToLeave);
+      Uint32 segmentsIVal= errorInsertHoardedSegments;
+      Uint32 space[SectionSegment::DataLength];
+      
+      while (numToAlloc-- > 0)
+        appendToSection(segmentsIVal, space, SectionSegment::DataLength);
+      
+      errorInsertHoardedSegments= segmentsIVal;
+    }
+  }
+
+  if (ERROR_INSERTED(8068) && 
+      (errorInsertHoardedSegments != RNIL))
+  {
+    /* Free the SegmentedSection buffers taken previously */
+    DEBUG("Freeing hoarded segments");
+    releaseSection(errorInsertHoardedSegments);
+    errorInsertHoardedSegments= RNIL;
+  }   
+
   /* Key and attribute lengths are passed in the header for 
    * short TCKEYREQ and  passed as section lengths for long 
    * TCKEYREQ
@@ -3947,10 +3989,11 @@
    * Dropped signal really means that we ran out of 
    * long signal buffering to store its sections
    */
+  jamEntry();
   const SignalDroppedRep* rep = (SignalDroppedRep*) &signal->theData[0];
   Uint32 originalGSN= rep->originalGsn;
 
-  jamEntry();
+  DEBUG("SignalDroppedRep received for GSN " << originalGSN);
 
   // TODO : Add handling for long signal variants as they
   //        are added here (TCINDXREQ, SCANTABREQ etc.)
@@ -3967,8 +4010,8 @@
      * have been truncated.  We must not read beyond
      * word # 22
      * We will send an Abort to the Api using info from
-     * the received signal and clean up our state for
-     * the transaction.
+     * the received signal and clean up our transaction 
+     * state
      */
     const TcKeyReq * const truncatedTcKeyReq = 
       (TcKeyReq *) &rep->originalData[0];
@@ -3982,22 +4025,38 @@
       return;
     }
     
-    /* Have a valid Api ConnectPtr...
+    /* We have a valid Api ConnectPtr...
+     * Ensure that we have the  necessary information 
+     * to send a rollback to the client
      */
     apiConnectptr.i = apiIndex;
     ApiConnectRecord * const regApiPtr = &apiConnectRecord[apiIndex];
     apiConnectptr.p = regApiPtr;
-
-    terrorCode= ZGET_DATAREC_ERROR; // Todo : New error?
-
-    abortErrorLab(signal); // Todo : Is this ok for TcIndxReq?
+    UintR transId1= truncatedTcKeyReq->transId1;
+    UintR transId2= truncatedTcKeyReq->transId2;
+    
+    /* Ensure that the apiConnectptr global is initialised
+     * may not be in cases where we drop the first signal of
+     * a transaction
+     */
+    apiConnectptr.p->transid[0] = transId1;
+    apiConnectptr.p->transid[1] = transId2;
+    apiConnectptr.p->returncode = ZGET_DATAREC_ERROR;
+
+    /* Set m_exec_flag according to the dropped request */
+    apiConnectptr.p->m_exec_flag = 
+      TcKeyReq::getExecuteFlag(truncatedTcKeyReq->requestInfo);
+
+    DEBUG("  Execute flag set to " << apiConnectptr.p->m_exec_flag);
+
+    abortErrorLab(signal);
 
     break;
   }
   default:
     jam();
     /* Don't expect dropped signals for other GSNs,
-     * handle as before
+     * default handling
      */
     SimulatedBlock::execSIGNAL_DROPPED_REP(signal);
   };
@@ -11206,6 +11265,7 @@
   apiConnectptr.p->apiConnectstate = CS_ABORTING;
   apiConnectptr.p->abortState = AS_IDLE;
   releaseAllSeizedIndexOperations(apiConnectptr.p);
+
   if(apiConnectptr.p->m_exec_flag || apiConnectptr.p->apiFailState == ZTRUE){
     jam();
     bool ok = false;
@@ -12893,7 +12953,7 @@
     jam();
     // Failed to seize keyInfo, abort transaction
 #ifdef VM_TRACE
-    ndbout_c("Dbtc::saveINDXKEYINFO: Failed to seize keyinfo\n");
+    ndbout_c("Dbtc::saveINDXKEYINFO: Failed to seize buffer for KeyInfo\n");
 #endif
     // Abort transaction
     apiConnectptr.i = indexOp->connectionIndex;
@@ -12936,7 +12996,7 @@
   {
     jam();
 #ifdef VM_TRACE
-    ndbout_c("Dbtc::saveINDXATTRINFO: Failed to seize attrInfo\n");
+    ndbout_c("Dbtc::saveINDXATTRINFO: Failed to seize buffer for attrInfo\n");
 #endif
     apiConnectptr.i = indexOp->connectionIndex;
     ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
@@ -13040,12 +13100,12 @@
       {
         jam();
 #ifdef VM_TRACE
-        ndbout_c("Dbtc::saveTRANSID_AI: Failed to add to section\n");
+        ndbout_c("Dbtc::saveTRANSID_AI: Failed to seize beffer for TRANSID_AI\n");
 #endif
         apiConnectptr.i = indexOp->connectionIndex;
         ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
         releaseIndexOperation(apiConnectptr.p, indexOp);
-        terrorCode = 4000;
+        terrorCode = ZGET_DATAREC_ERROR;
         abortErrorLab(signal);
         return false;
       }

=== modified file 'storage/ndb/src/kernel/vm/SimulatedBlock.cpp'
--- a/storage/ndb/src/kernel/vm/SimulatedBlock.cpp	2008-06-17 20:28:45 +0000
+++ b/storage/ndb/src/kernel/vm/SimulatedBlock.cpp	2008-07-01 12:35:34 +0000
@@ -328,6 +328,9 @@
   if (len == 0) 
     return true;  
 
+  Uint32 remain= SectionSegment::DataLength;
+  Uint32 segmentLen= 0;
+
   if (firstSegmentIVal == RNIL)
   {
     /* First data to be added to this section */
@@ -349,15 +352,27 @@
     /* Section has at least one segment with data already */
     g_sectionSegmentPool.getPtr(firstPtr, firstSegmentIVal);
     g_sectionSegmentPool.getPtr(currPtr, firstPtr.p->m_lastSegment);
+
+    Uint32 existingLen= firstPtr.p->m_sz;
+    assert(existingLen > 0);
+    segmentLen= existingLen % SectionSegment::DataLength;
+    
+    /* If existingLen %  SectionSegment::DataLength == 0
+     * we assume that the last segment is full
+     */
+    segmentLen= segmentLen == 0 ? 
+      SectionSegment::DataLength :
+      segmentLen;
+
+    remain= SectionSegment::DataLength - segmentLen;
   }
 
-  Uint32 existingLen= firstPtr.p->m_sz;
   firstPtr.p->m_sz+= len;
-  Uint32 segmentLen= existingLen % SectionSegment::DataLength;
-  Uint32 remain= SectionSegment::DataLength - segmentLen;
 
   while(len > remain) {
-    /* Fill this segment, and link in another one */
+    /* Fill this segment, and link in another one 
+     * Note that we can memcpy to a bad address with size 0
+     */
     memcpy(&currPtr.p->theData[segmentLen], src, remain << 2);
     src += remain;
     len -= remain;

=== modified file 'storage/ndb/src/kernel/vm/TransporterCallback.cpp'
--- a/storage/ndb/src/kernel/vm/TransporterCallback.cpp	2008-06-18 09:04:21 +0000
+++ b/storage/ndb/src/kernel/vm/TransporterCallback.cpp	2008-07-01 12:35:34 +0000
@@ -84,7 +84,7 @@
     ;
   } else {
     MT_SECTION_UNLOCK
-    ndbout_c("here");
+    ndbout_c("No Segmented Sections for import");
     return false;
   }
 
@@ -103,9 +103,12 @@
     if(g_sectionSegmentPool.seize(currPtr)){
       ;
     } else {
+      /* Leave segment chain in ok condition for release */
       first.p->m_lastSegment = prevPtr.i;
+      first.p->m_sz-= len;
+      prevPtr.p->m_nextSegment = RNIL;
       MT_SECTION_UNLOCK
-      ndbout_c("hera");
+      ndbout_c("Not enough Segmented Sections during import");
       return false;
     }
   }
@@ -200,6 +203,8 @@
 
   bool ok = true;
   Ptr<SectionSegment> secPtr[3];
+  secPtr[0].p = secPtr[1].p = secPtr[2].p = 0;
+
   switch(secCount){
   case 3:
     ok &= import(secPtr[2], ptr[2].p, ptr[2].sz);
@@ -243,7 +248,8 @@
   MT_SECTION_LOCK
   for(Uint32 i = 0; i<secCount; i++){
     if(secPtr[i].p != 0){
-      g_sectionSegmentPool.releaseList(relSz(ptr[i].sz), secPtr[i].i, 
+      g_sectionSegmentPool.releaseList(relSz(secPtr[i].p->m_sz), 
+                                       secPtr[i].i, 
 				       secPtr[i].p->m_lastSegment);
     }
   }

=== modified file 'storage/ndb/test/include/NDBT_Table.hpp'
--- a/storage/ndb/test/include/NDBT_Table.hpp	2007-04-03 12:49:05 +0000
+++ b/storage/ndb/test/include/NDBT_Table.hpp	2008-07-01 12:35:34 +0000
@@ -73,6 +73,23 @@
     assert(ret == 0);
   }
 
+  NDBT_Table(const char* name, 
+	     int noOfAttributes,
+	     NdbDictionary::Column* attributePtrs[])
+    : NdbDictionary::Table(name)
+  {
+    assert(name != 0);
+    
+    //setStoredTable(stored);
+    for(int i = 0; i<noOfAttributes; i++)
+      addColumn(*attributePtrs[i]);
+    
+    // validate() might cause initialization order problem with charset
+    NdbError error;
+    int ret = aggregate(error);
+    assert(ret == 0);
+  }
+  
   static const NdbDictionary::Table * discoverTableFromDb(Ndb* ndb,
 							  const char * name);
 };

=== modified file 'storage/ndb/test/include/NDBT_Tables.hpp'
--- a/storage/ndb/test/include/NDBT_Tables.hpp	2006-12-23 19:20:40 +0000
+++ b/storage/ndb/test/include/NDBT_Tables.hpp	2008-07-01 12:35:34 +0000
@@ -27,6 +27,27 @@
 
 class NDBT_Tables {
 public:
+  /* Some constants for the maximum sizes of keys and attributes
+   * in various cases
+   */
+  STATIC_CONST(MaxRowBytes= NDB_MAX_TUPLE_SIZE_IN_WORDS * 4);
+  STATIC_CONST(MaxKeyBytes= NDB_MAX_KEYSIZE_IN_WORDS * 4);
+  STATIC_CONST(MinKeyBytes= 4); // Single Unsigned key
+
+  STATIC_CONST(MaxVarTypeKeyBytes= MaxKeyBytes - 2); // 2 length bytes
+
+  STATIC_CONST(MaxKeyMaxAttrBytes= MaxRowBytes - MaxKeyBytes);
+  STATIC_CONST(MaxKeyMaxVarTypeAttrBytes= MaxKeyMaxAttrBytes - 2);
+
+  STATIC_CONST(MinKeyMaxAttrBytes= MaxRowBytes - MinKeyBytes);
+  STATIC_CONST(MinKeyMaxVarTypeAttrBytes= MinKeyMaxAttrBytes - 2);
+
+  STATIC_CONST(UniqueIndexOverheadBytes= 4); // For FragId
+  STATIC_CONST(MaxKeyMaxVarTypeAttrBytesIndex = 
+               MaxKeyMaxVarTypeAttrBytes - UniqueIndexOverheadBytes);
+
+  /* Hugo requires 2 unsigned int columns somewhere in the table */
+  STATIC_CONST(HugoOverheadBytes= 2 * 4); 
 
   static int createTable(Ndb* pNdb, const char* _name, bool _temp = false, 
 			 bool existsOK = false, NDBT_CreateTableHook = 0,

=== modified file 'storage/ndb/test/ndbapi/Makefile.am'
--- a/storage/ndb/test/ndbapi/Makefile.am	2008-06-05 20:19:01 +0000
+++ b/storage/ndb/test/ndbapi/Makefile.am	2008-07-01 12:35:34 +0000
@@ -31,6 +31,7 @@
 testDataBuffers \
 testDict \
 testIndex \
+testLimits \
 testMgm \
 testNdbApi \
 testNodeRestart \
@@ -83,6 +84,7 @@
 testDataBuffers_SOURCES = testDataBuffers.cpp
 testDict_SOURCES = testDict.cpp
 testIndex_SOURCES = testIndex.cpp
+testLimits_SOURCES = testLimits.cpp
 testMgm_SOURCES = testMgm.cpp
 testNdbApi_SOURCES = testNdbApi.cpp
 testNodeRestart_SOURCES = testNodeRestart.cpp

=== added file 'storage/ndb/test/ndbapi/testLimits.cpp'
--- a/storage/ndb/test/ndbapi/testLimits.cpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/ndbapi/testLimits.cpp	2008-07-01 12:35:34 +0000
@@ -0,0 +1,828 @@
+/* Copyright (C) 2003 MySQL AB
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#include <NDBT.hpp>
+#include <NDBT_Test.hpp>
+#include <NdbRestarter.hpp>
+
+#define CHECKNOTNULL(p) if ((p) == NULL) {          \
+    ndbout << "Error at line " << __LINE__ << endl; \
+    ERR(trans->getNdbError());                      \
+    return NDBT_FAILED; }
+
+#define CHECKEQUAL(v, e) if ((e) != (v)) {            \
+    ndbout << "Error at line " << __LINE__ <<         \
+      " expected " << v << endl;                      \
+    ERR(trans->getNdbError());                        \
+    return NDBT_FAILED; }
+
+
+/* Setup memory as a long Varchar with 2 bytes of
+ * length information
+ */
+Uint32 setLongVarchar(char* where, const char* what, Uint32 sz)
+{
+  where[0]=sz & 0xff;
+  where[1]=(sz >> 8) & 0xff;
+  memcpy(&where[2], what, sz);
+  return (sz + 2);
+}
+
+
+/* Activate the given error insert in TC block
+ * This is used for error insertion where a TCKEYREQ
+ * is required to activate the error
+ */
+int activateErrorInsert(NdbTransaction* trans, 
+                        const NdbRecord* record,
+                        const NdbDictionary::Table* tab,
+                        const char* buf,
+                        NdbRestarter* restarter, 
+                        Uint32 val)
+{
+  if (restarter->insertErrorInAllNodes(val) != 0){
+    g_err << "error insert (val) failed" << endl;
+    return NDBT_FAILED;
+  }
+
+  NdbOperation* insert= trans->getNdbOperation(tab);
+  
+  CHECKNOTNULL(insert);
+
+  CHECKEQUAL(0, insert->insertTuple());
+
+  CHECKEQUAL(0, insert->equal((Uint32) 0, 
+                              NdbDictionary::getValuePtr
+                              (record,
+                               buf,
+                               0)));
+  CHECKEQUAL(0, insert->setValue(1,
+                                 NdbDictionary::getValuePtr
+                                 (record,
+                                  buf,
+                                  1)));
+
+  CHECKEQUAL(0, trans->execute(NdbTransaction::NoCommit));
+
+  CHECKEQUAL(0, trans->getNdbError().code);
+
+  return NDBT_OK;
+}
+    
+/* Test for correct behaviour using primary key operations
+ * when an NDBD node's SegmentedSection pool is exhausted.
+ * Long and Short TCKEYREQ variants are tested
+ */
+int testSegmentedSectionPk(NDBT_Context* ctx, NDBT_Step* step){
+  /*
+   * Signal type       Exhausted @              How
+   * -----------------------------------------------------
+   * Long TCKEYREQ     Initial import           Consume + send
+   * Long TCKEYREQ     Initial import, not first
+   *                     TCKEYREQ in batch      Consume + send
+   * Long TCKEYREQ     Initial import, not last
+   *                     TCKEYREQ in batch      Consume + send
+   * Short TCKEYREQ    KeyInfo accumulate       Consume + send long
+   *                     (TCKEYREQ + KEYINFO)
+   * Short TCKEYREQ    AttrInfo accumulate      Consume + send short key
+   *                                             + long AI
+   *                      (TCKEYREQ + ATTRINFO)
+   */
+
+  /* We just run on one table */
+  if (strcmp(ctx->getTab()->getName(), "WIDE_2COL") != 0)
+    return NDBT_OK;
+
+  const Uint32 maxRowBytes= NDB_MAX_TUPLE_SIZE_IN_WORDS * sizeof(Uint32);
+  const Uint32 srcBuffBytes= NDBT_Tables::MaxVarTypeKeyBytes;
+  const Uint32 maxAttrBytes= NDBT_Tables::MaxKeyMaxVarTypeAttrBytes;
+  char smallKey[50];
+  char srcBuff[srcBuffBytes];
+  char smallRowBuf[maxRowBytes];
+  char bigKeyRowBuf[maxRowBytes];
+  char bigAttrRowBuf[maxRowBytes];
+
+  /* Small key for hinting to same TC */
+  Uint32 smallKeySize= setLongVarchar(&smallKey[0],
+                                      "ShortKey",
+                                      8);
+
+  /* Large value source */
+  memset(srcBuff, 'B', srcBuffBytes);
+
+  const NdbRecord* record= ctx->getTab()->getDefaultRecord();
+
+  /* Setup buffers
+   * Small row buffer with small key and small data
+   */ 
+  setLongVarchar(NdbDictionary::getValuePtr(record,
+                                            smallRowBuf,
+                                            0),
+                 "ShortKey",
+                 8);
+  NdbDictionary::setNull(record, smallRowBuf, 0, false);
+
+  setLongVarchar(NdbDictionary::getValuePtr(record,
+                                            smallRowBuf,
+                                            1),
+                 "ShortData",
+                 9);
+  NdbDictionary::setNull(record, smallRowBuf, 1, false);
+
+  /* Big key buffer with big key and small data*/
+  setLongVarchar(NdbDictionary::getValuePtr(record,
+                                            bigKeyRowBuf,
+                                            0),
+                 &srcBuff[0],
+                 srcBuffBytes);
+  NdbDictionary::setNull(record, bigKeyRowBuf, 0, false);
+
+  setLongVarchar(NdbDictionary::getValuePtr(record,
+                                            bigKeyRowBuf,
+                                            1),
+                 "ShortData",
+                 9);
+  NdbDictionary::setNull(record, bigKeyRowBuf, 1, false);
+
+  /* Big AttrInfo buffer with small key and big data */
+  setLongVarchar(NdbDictionary::getValuePtr(record,
+                                            bigAttrRowBuf,
+                                            0),
+                 "ShortKey", 
+                 8);
+  NdbDictionary::setNull(record, bigAttrRowBuf, 0, false);
+
+  setLongVarchar(NdbDictionary::getValuePtr(record,
+                                            bigAttrRowBuf,
+                                            1),
+                 &srcBuff[0],
+                 maxAttrBytes);
+  NdbDictionary::setNull(record, bigAttrRowBuf, 1, false);
+
+  NdbRestarter restarter;
+  Ndb* pNdb= GETNDB(step);
+
+  /* Start a transaction on a specific node */
+  NdbTransaction* trans= pNdb->startTransaction(ctx->getTab(),
+                                                &smallKey[0],
+                                                smallKeySize);
+  CHECKNOTNULL(trans);
+
+  /* Activate error insert 8065 in this transaction, consumes
+   * all but 10 SectionSegments
+   */
+  CHECKEQUAL(NDBT_OK, activateErrorInsert(trans, 
+                                          record, 
+                                          ctx->getTab(),
+                                          smallRowBuf, 
+                                          &restarter, 
+                                          8065));
+
+  /* Ok, now the chosen TC's node should have only 10 
+   * SegmentedSection buffers = ~ 60 words * 10 = 2400 bytes
+   * Let's try an insert with a key bigger than that
+   * Since it's part of the same transaction, it'll go via
+   * the same TC.
+   */
+  const NdbOperation* bigInsert = trans->insertTuple(record, bigKeyRowBuf);
+
+  CHECKNOTNULL(bigInsert);
+
+  CHECKEQUAL(-1, trans->execute(NdbTransaction::NoCommit));
+
+  /* ZGET_DATABUF_ERR expected */
+  CHECKEQUAL(218, trans->getNdbError().code)
+
+  trans->close();
+  
+  /* Ok, now a long TCKEYREQ to the same TC - this
+   * has slightly different abort handling since no other
+   * operations exist in this new transaction.
+   * We also change it so that import overflow occurs 
+   * on the AttrInfo section
+   */
+  /* Start transaction on the same node */
+  CHECKNOTNULL(trans= pNdb->startTransaction(ctx->getTab(),
+                                             &smallKey[0],
+                                             smallKeySize));
+
+
+  CHECKNOTNULL(bigInsert = trans->insertTuple(record, bigAttrRowBuf));
+
+  CHECKEQUAL(-1,trans->execute(NdbTransaction::NoCommit));
+
+  /* ZGET_DATABUF_ERR expected */
+  CHECKEQUAL(218, trans->getNdbError().code);
+
+  trans->close();
+
+  /* Ok, now a long TCKEYREQ where we run out of SegmentedSections
+   * on the first TCKEYREQ, but there are other TCKEYREQs following
+   * in the same batch.  Check that abort handling is correct
+   */
+    /* Start transaction on the same node */
+  CHECKNOTNULL(trans= pNdb->startTransaction(ctx->getTab(),
+                                             &smallKey[0],
+                                             smallKeySize));
+  /* First op in batch, will cause overflow */
+  CHECKNOTNULL(bigInsert = trans->insertTuple(record, bigAttrRowBuf));
+  
+  /* Second op in batch, what happens to it? */
+  const NdbOperation* secondOp;
+  CHECKNOTNULL(secondOp = trans->insertTuple(record, bigAttrRowBuf));
+
+
+  CHECKEQUAL(-1,trans->execute(NdbTransaction::NoCommit));
+
+  /* ZGET_DATABUF_ERR expected */
+  CHECKEQUAL(218, trans->getNdbError().code);
+
+  trans->close();
+
+  /* Now try with a 'short' TCKEYREQ, generated using the old Api 
+   * with a big key value
+   */
+  /* Start transaction on the same node */
+  CHECKNOTNULL(trans= pNdb->startTransaction(ctx->getTab(),
+                                             &smallKey[0],
+                                             smallKeySize));
+  
+  NdbOperation* bigInsertOldApi;
+  CHECKNOTNULL(bigInsertOldApi= trans->getNdbOperation(ctx->getTab()));
+
+  CHECKEQUAL(0, bigInsertOldApi->insertTuple());
+  CHECKEQUAL(0, bigInsertOldApi->equal((Uint32)0, 
+                                       NdbDictionary::getValuePtr
+                                       (record,
+                                        bigKeyRowBuf,
+                                        0)));
+  CHECKEQUAL(0, bigInsertOldApi->setValue(1, 
+                                          NdbDictionary::getValuePtr
+                                          (record,
+                                           bigKeyRowBuf,
+                                           1)));
+
+  CHECKEQUAL(-1, trans->execute(NdbTransaction::NoCommit));
+
+  /* ZGET_DATABUF_ERR expected */
+  CHECKEQUAL(218, trans->getNdbError().code)
+
+  trans->close();
+
+  /* Now try with a 'short' TCKEYREQ, generated using the old Api 
+   * with a big data value
+   */
+  CHECKNOTNULL(trans= pNdb->startTransaction(ctx->getTab(),
+                                             &smallKey[0],
+                                             smallKeySize));
+  
+  CHECKNOTNULL(bigInsertOldApi= trans->getNdbOperation(ctx->getTab()));
+
+  CHECKEQUAL(0, bigInsertOldApi->insertTuple());
+  CHECKEQUAL(0, bigInsertOldApi->equal((Uint32)0, 
+                                       NdbDictionary::getValuePtr
+                                       (record,
+                                        bigAttrRowBuf,
+                                        0)));
+  CHECKEQUAL(0, bigInsertOldApi->setValue(1, 
+                                          NdbDictionary::getValuePtr
+                                          (record,
+                                           bigAttrRowBuf,
+                                           1)));
+
+  CHECKEQUAL(-1, trans->execute(NdbTransaction::NoCommit));
+
+  /* ZGET_DATABUF_ERR expected */
+  CHECKEQUAL(218, trans->getNdbError().code)
+
+  trans->close();
+
+  /* Change error insert so that next TCKEYREQ will grab
+   * all but one SegmentedSection so that we can then test SegmentedSection
+   * exhaustion when importing the Key/AttrInfo words from the
+   * TCKEYREQ signal itself.
+   */
+  restarter.insertErrorInAllNodes(8066);
+
+
+  /* Now a 'short' TCKEYREQ, there will be space to import the
+   * short key, but not the AttrInfo
+   */
+  /* Start transaction on same node */
+  CHECKNOTNULL(trans= pNdb->startTransaction(ctx->getTab(),
+                                             &smallKey[0],
+                                             smallKeySize));
+  
+  CHECKNOTNULL(bigInsertOldApi= trans->getNdbOperation(ctx->getTab()));
+  
+  CHECKEQUAL(0, bigInsertOldApi->insertTuple());
+  CHECKEQUAL(0, bigInsertOldApi->equal((Uint32)0, 
+                                       NdbDictionary::getValuePtr
+                                       (record,
+                                        smallRowBuf,
+                                        0)));
+  CHECKEQUAL(0, bigInsertOldApi->setValue(1, NdbDictionary::getValuePtr
+                                          (record,
+                                           smallRowBuf,
+                                           1)));
+
+  CHECKEQUAL(-1, trans->execute(NdbTransaction::NoCommit));
+
+  /* ZGET_DATABUF_ERR expected */
+  CHECKEQUAL(218, trans->getNdbError().code)
+
+  trans->close();
+
+  /* Change error insert so that there are no SectionSegments 
+   * This will cause failure when attempting to import the
+   * KeyInfo from the TCKEYREQ
+   */
+  restarter.insertErrorInAllNodes(8067);
+
+  /* Now a 'short' TCKEYREQ - there will be no space to import the key */
+  CHECKNOTNULL(trans= pNdb->startTransaction(ctx->getTab(),
+                                             &smallKey[0],
+                                             smallKeySize));
+  
+  CHECKNOTNULL(bigInsertOldApi= trans->getNdbOperation(ctx->getTab()));
+  
+  CHECKEQUAL(0, bigInsertOldApi->insertTuple());
+  CHECKEQUAL(0, bigInsertOldApi->equal((Uint32)0, 
+                                       NdbDictionary::getValuePtr
+                                       (record,
+                                        smallRowBuf,
+                                        0)));
+  CHECKEQUAL(0, bigInsertOldApi->setValue(1, 
+                                          NdbDictionary::getValuePtr
+                                          (record,
+                                           smallRowBuf,
+                                           1)));
+
+  CHECKEQUAL(-1, trans->execute(NdbTransaction::NoCommit));
+
+  /* ZGET_DATABUF_ERR expected */
+  CHECKEQUAL(218, trans->getNdbError().code)
+
+  trans->close();  
+
+
+  /* Finished with error insert, cleanup the error insertion
+   * Error insert 8068 will free the hoarded segments
+   */
+  CHECKNOTNULL(trans= pNdb->startTransaction(ctx->getTab(),
+                                             &smallKey[0],
+                                             smallKeySize));
+
+  CHECKEQUAL(NDBT_OK, activateErrorInsert(trans, 
+                                          record, 
+                                          ctx->getTab(),
+                                          smallRowBuf, 
+                                          &restarter, 
+                                          8068));
+
+  trans->execute(NdbTransaction::Rollback);
+  
+  CHECKEQUAL(0, trans->getNdbError().code);
+
+  trans->close();
+
+  return NDBT_OK;
+}
+  
+/* Test for correct behaviour using unique key operations
+ * when an NDBD node's SegmentedSection pool is exhausted.
+ * Long and Short TCKEYREQ variants are tested
+ */
+int testSegmentedSectionIx(NDBT_Context* ctx, NDBT_Step* step){
+  /* 
+   * Signal type       Exhausted @              How
+   * -----------------------------------------------------
+   * Long TCINDXREQ    Initial import           Consume + send 
+   * Long TCINDXREQ    Build second TCKEYREQ    Consume + send short
+   *                                             w. long base key
+   * Short TCINDXREQ   KeyInfo accumulate       Consume + send long
+   *                     (TCINDXREQ + KEYINFO)
+   * Short TCINDXREQ   AttrInfo accumulate      Consume + send short key
+   *                                             + long AI
+   *                     (TCINDXREQ + ATTRINFO)
+   */
+  /* We will generate : 
+   *   10 SS left : 
+   *     Long IndexReq with too long Key/AttrInfo
+   *     Long IndexReq read with short Key + Attrinfo to long 
+   *       base table Key
+   *     Short IndexReq with long Keyinfo
+   *     Short IndexReq with long AttrInfo
+   *   1 SS left
+   *     Short IndexReq with any AttrInfo
+   *   0 SS left
+   *     Short IndexReq with any key info 
+   */
+  /* We just run on one table */
+  if (strcmp(ctx->getTab()->getName(), "WIDE_2COL_IX") != 0)
+    return NDBT_OK;
+
+  const char* indexName= "WIDE_2COL_IX$NDBT_IDX0";
+  const Uint32 maxRowBytes= NDB_MAX_TUPLE_SIZE_IN_WORDS * sizeof(Uint32);
+  const Uint32 srcBuffBytes= NDBT_Tables::MaxVarTypeKeyBytes;
+  const Uint32 maxIndexKeyBytes= NDBT_Tables::MaxKeyMaxVarTypeAttrBytesIndex;
+  /* We want to use 6 Segmented Sections, each of 60 32-bit words, including
+   * a 2 byte length overhead
+   * (We don't want to use 10 Segmented Sections as in some scenarios TUP 
+   *  uses Segmented Sections when sending results, and if we use TUP on
+   *  the same node, the exhaustion will occur in TUP, which is not what
+   *  we're testing)
+   */
+  const Uint32 mediumPrimaryKeyBytes= (6* 60 * 4) - 2;
+  char smallKey[50];
+  char srcBuff[srcBuffBytes];
+  char smallRowBuf[maxRowBytes];
+  char bigKeyIxBuf[maxRowBytes];
+  char bigAttrIxBuf[maxRowBytes];
+  char bigKeyRowBuf[maxRowBytes];
+  char resultSpace[maxRowBytes];
+
+  /* Small key for hinting to same TC */
+  Uint32 smallKeySize= setLongVarchar(&smallKey[0],
+                                      "ShortKey",
+                                      8);
+
+  /* Large value source */
+  memset(srcBuff, 'B', srcBuffBytes);
+
+  Ndb* pNdb= GETNDB(step);
+
+  const NdbRecord* baseRecord= ctx->getTab()->getDefaultRecord();
+  const NdbRecord* ixRecord= pNdb->
+    getDictionary()->getIndex(indexName,
+                              ctx->getTab()->getName())->getDefaultRecord();
+
+  /* Setup buffers
+   * Small row buffer with short key and data in base table record format
+   */ 
+  setLongVarchar(NdbDictionary::getValuePtr(baseRecord,
+                                            smallRowBuf,
+                                            0),
+                 "ShortKey",
+                 8);
+  NdbDictionary::setNull(baseRecord, smallRowBuf, 0, false);
+
+  setLongVarchar(NdbDictionary::getValuePtr(baseRecord,
+                                            smallRowBuf,
+                                            1),
+                 "ShortData",
+                 9);
+  NdbDictionary::setNull(baseRecord, smallRowBuf, 1, false);
+
+  /* Big index key buffer
+   * Big index key (normal row attribute) in index record format
+   * Index's key is attrid 1 from the base table
+   * This could get confusing !
+   */
+  
+  setLongVarchar(NdbDictionary::getValuePtr(ixRecord,
+                                            bigKeyIxBuf,
+                                            1),
+                 &srcBuff[0],
+                 maxIndexKeyBytes);
+  NdbDictionary::setNull(ixRecord, bigKeyIxBuf, 1, false);
+
+  /* Big AttrInfo buffer
+   * Small key and large attrinfo in base table record format */
+  setLongVarchar(NdbDictionary::getValuePtr(baseRecord,
+                                            bigAttrIxBuf,
+                                            0),
+                 "ShortIXKey", 
+                 10);
+
+  NdbDictionary::setNull(baseRecord, bigAttrIxBuf, 0, false);
+
+  setLongVarchar(NdbDictionary::getValuePtr(baseRecord,
+                                            bigAttrIxBuf,
+                                            1),
+                 &srcBuff[0],
+                 maxIndexKeyBytes);
+  NdbDictionary::setNull(baseRecord, bigAttrIxBuf, 1, false);
+
+  /* Big key row buffer 
+   * Medium sized key and small attrinfo (index key) in
+   * base table record format
+   */
+  setLongVarchar(NdbDictionary::getValuePtr(baseRecord,
+                                            bigKeyRowBuf,
+                                            0),
+                 &srcBuff[0], 
+                 mediumPrimaryKeyBytes);
+
+  NdbDictionary::setNull(baseRecord, bigKeyRowBuf, 0, false);
+
+  setLongVarchar(NdbDictionary::getValuePtr(baseRecord,
+                                            bigKeyRowBuf,
+                                            1),
+                 "ShortIXKey",
+                 10);
+  NdbDictionary::setNull(baseRecord, bigKeyRowBuf, 1, false);
+
+
+  /* Start a transaction on a specific node */
+  NdbTransaction* trans= pNdb->startTransaction(ctx->getTab(),
+                                                &smallKey[0],
+                                                smallKeySize);
+  /* Insert a row in the base table with a big PK, and
+   * small data (Unique IX key).  This is used later to lookup
+   * a big PK and cause overflow when reading TRANSID_AI in TC.
+   */
+  CHECKNOTNULL(trans->insertTuple(baseRecord,
+                                  bigKeyRowBuf));
+
+  CHECKEQUAL(0, trans->execute(NdbTransaction::Commit));
+
+  NdbRestarter restarter;
+  /* Start a transaction on a specific node */
+  trans= pNdb->startTransaction(ctx->getTab(),
+                                &smallKey[0],
+                                smallKeySize);
+  CHECKNOTNULL(trans);
+
+  /* Activate error insert 8065 in this transaction, consumes
+   * all but 10 SectionSegments
+   */
+  CHECKEQUAL(NDBT_OK, activateErrorInsert(trans, 
+                                          baseRecord, 
+                                          ctx->getTab(),
+                                          smallRowBuf, 
+                                          &restarter, 
+                                          8065));
+
+  /* Ok, now the chosen TC's node should have only 10 
+   * SegmentedSection buffers = ~ 60 words * 10 = 2400 bytes
+   * Let's try an index read with an index key bigger than that
+   * Since it's part of the same transaction, it'll go via
+   * the same TC.
+   */
+  const NdbOperation* bigRead= trans->readTuple(ixRecord,
+                                                bigKeyIxBuf,
+                                                baseRecord,
+                                                resultSpace);
+
+  CHECKNOTNULL(bigRead);
+
+  CHECKEQUAL(-1, trans->execute(NdbTransaction::NoCommit));
+
+  /* ZGET_DATABUF_ERR expected */
+  CHECKEQUAL(218, trans->getNdbError().code)
+
+  trans->close();
+
+  
+  /* Ok, now a long TCINDXREQ to the same TC - this
+   * has slightly different abort handling since no other
+   * operations exist in this new transaction.
+   */
+  /* Start a transaction on a specific node */
+  CHECKNOTNULL(trans= pNdb->startTransaction(ctx->getTab(),
+                                             &smallKey[0],
+                                             smallKeySize));
+
+  CHECKNOTNULL(trans->readTuple(ixRecord,
+                                bigKeyIxBuf,
+                                baseRecord,
+                                resultSpace));
+  
+  CHECKEQUAL(-1, trans->execute(NdbTransaction::NoCommit));
+
+  /* ZGET_DATABUF_ERR expected */
+  CHECKEQUAL(218, trans->getNdbError().code);
+  
+  trans->close();
+
+  /* Now a TCINDXREQ that overflows, but is not the last in the
+   * batch, what happens to the other TCINDXREQ in the batch?
+   */
+  CHECKNOTNULL(trans= pNdb->startTransaction(ctx->getTab(),
+                                             &smallKey[0],
+                                             smallKeySize));
+
+  CHECKNOTNULL(trans->readTuple(ixRecord,
+                                bigKeyIxBuf,
+                                baseRecord,
+                                resultSpace));
+  /* Another read */
+  CHECKNOTNULL(trans->readTuple(ixRecord,
+                                bigKeyIxBuf,
+                                baseRecord,
+                                resultSpace));
+  
+  CHECKEQUAL(-1, trans->execute(NdbTransaction::NoCommit));
+
+  /* ZGET_DATABUF_ERR expected */
+  CHECKEQUAL(218, trans->getNdbError().code);
+  
+  trans->close();
+
+
+  /* Next we read a tuple with a large primary key via the unique
+   * index.  The index read itself should be fine, but
+   * pulling in the base table PK will cause abort due to overflow
+   * handling TRANSID_AI
+   */
+  /* Start a transaction on a specific node */
+  CHECKNOTNULL(trans= pNdb->startTransaction(ctx->getTab(),
+                                             &smallKey[0],
+                                             smallKeySize));
+
+  CHECKNOTNULL(bigRead= trans->readTuple(ixRecord,
+                                         bigAttrIxBuf,
+                                         baseRecord,
+                                         resultSpace));
+
+  CHECKEQUAL(-1, trans->execute(NdbTransaction::NoCommit));
+
+  /* ZGET_DATABUF_ERR expected */
+  CHECKEQUAL(218, trans->getNdbError().code)
+
+  trans->close();
+
+  /* Now try with a 'short' TCINDXREQ, generated using the old Api 
+   * with a big index key value
+   */
+  CHECKNOTNULL(trans= pNdb->startTransaction(ctx->getTab(),
+                                             &smallKey[0],
+                                             smallKeySize));
+  
+  const NdbDictionary::Index* index;
+  CHECKNOTNULL(index= pNdb->getDictionary()->
+               getIndex(indexName,
+                        ctx->getTab()->getName()));
+
+  NdbIndexOperation* bigReadOldApi;
+  CHECKNOTNULL(bigReadOldApi= trans->getNdbIndexOperation(index));
+
+  CHECKEQUAL(0, bigReadOldApi->readTuple());
+  /* We use the attribute id of the index, not the base table here */
+  CHECKEQUAL(0, bigReadOldApi->equal((Uint32)0, 
+                                     NdbDictionary::getValuePtr
+                                     (ixRecord,
+                                      bigKeyIxBuf,
+                                      1)));
+
+  CHECKNOTNULL(bigReadOldApi->getValue((Uint32)1));
+
+  CHECKEQUAL(-1, trans->execute(NdbTransaction::NoCommit));
+
+  /* ZGET_DATABUF_ERR expected */
+  CHECKEQUAL(218, trans->getNdbError().code)
+
+  trans->close();
+
+  /* Now try with a 'short' TCINDXREQ, generated using the old Api 
+   * with a big attrinfo value
+   */
+  CHECKNOTNULL(trans= pNdb->startTransaction(ctx->getTab(),
+                                             &smallKey[0],
+                                             smallKeySize));
+  
+  NdbIndexOperation* bigUpdateOldApi;
+  CHECKNOTNULL(bigUpdateOldApi= trans->getNdbIndexOperation(index));
+
+  CHECKEQUAL(0, bigUpdateOldApi->updateTuple());
+  /* We use the attribute id of the index, not the base table here */
+  CHECKEQUAL(0, bigUpdateOldApi->equal((Uint32)0, 
+                                       NdbDictionary::getValuePtr
+                                       (baseRecord,
+                                        smallRowBuf,
+                                        1)));
+
+  CHECKEQUAL(0, bigUpdateOldApi->setValue((Uint32)1,
+                                          NdbDictionary::getValuePtr
+                                          (baseRecord,
+                                           bigAttrIxBuf,
+                                           1)));
+  
+  CHECKEQUAL(-1, trans->execute(NdbTransaction::NoCommit));
+
+  /* ZGET_DATABUF_ERR expected */
+  CHECKEQUAL(218, trans->getNdbError().code)
+
+  trans->close();
+
+  /* Change error insert so that next TCINDXREQ will grab
+   * all but one SegmentedSection
+   */
+  restarter.insertErrorInAllNodes(8066);
+
+  /* Now a short TCINDXREQ where the KeyInfo from the TCINDXREQ
+   * can be imported, but the ATTRINFO can't
+   */
+  CHECKNOTNULL(trans= pNdb->startTransaction(ctx->getTab(),
+                                             &smallKey[0],
+                                             smallKeySize));
+  
+  CHECKNOTNULL(bigUpdateOldApi= trans->getNdbIndexOperation(index));
+
+  CHECKEQUAL(0, bigUpdateOldApi->updateTuple());
+  /* We use the attribute id of the index, not the base table here */
+  CHECKEQUAL(0, bigUpdateOldApi->equal((Uint32)0, 
+                                       NdbDictionary::getValuePtr
+                                       (baseRecord,
+                                        smallRowBuf,
+                                        1)));
+
+  CHECKEQUAL(0, bigUpdateOldApi->setValue((Uint32)1,
+                                          NdbDictionary::getValuePtr
+                                          (baseRecord,
+                                           bigAttrIxBuf,
+                                           1)));
+  
+  CHECKEQUAL(-1, trans->execute(NdbTransaction::NoCommit));
+
+  /* ZGET_DATABUF_ERR expected */
+  CHECKEQUAL(218, trans->getNdbError().code)
+
+  trans->close();
+
+  /* Change error insert so that there are no SectionSegments */
+  restarter.insertErrorInAllNodes(8067);
+
+  /* Now a short TCINDXREQ where the KeyInfo from the TCINDXREQ
+   * can't be imported
+   */
+  CHECKNOTNULL(trans= pNdb->startTransaction(ctx->getTab(),
+                                             &smallKey[0],
+                                             smallKeySize));
+
+  CHECKNOTNULL(bigUpdateOldApi= trans->getNdbIndexOperation(index));
+
+  CHECKEQUAL(0, bigUpdateOldApi->updateTuple());
+  /* We use the attribute id of the index, not the base table here */
+  CHECKEQUAL(0, bigUpdateOldApi->equal((Uint32)0, 
+                                       NdbDictionary::getValuePtr
+                                       (baseRecord,
+                                        smallRowBuf,
+                                        1)));
+
+  CHECKEQUAL(0, bigUpdateOldApi->setValue((Uint32)1,
+                                          NdbDictionary::getValuePtr
+                                          (baseRecord,
+                                           bigAttrIxBuf,
+                                           1)));
+  
+  CHECKEQUAL(-1, trans->execute(NdbTransaction::NoCommit));
+
+  /* ZGET_DATABUF_ERR expected */
+  CHECKEQUAL(218, trans->getNdbError().code)
+
+  trans->close();
+
+  /* Finished with error insert, cleanup the error insertion */
+  CHECKNOTNULL(trans= pNdb->startTransaction(ctx->getTab(),
+                                             &smallKey[0],
+                                             smallKeySize));
+
+  CHECKEQUAL(NDBT_OK, activateErrorInsert(trans, 
+                                          baseRecord, 
+                                          ctx->getTab(),
+                                          smallRowBuf, 
+                                          &restarter, 
+                                          8068));
+
+  trans->execute(NdbTransaction::Rollback);
+  
+  CHECKEQUAL(0, trans->getNdbError().code);
+
+  trans->close();
+
+  return NDBT_OK;
+}
+
+
+NDBT_TESTSUITE(testLimits);
+
+TESTCASE("ExhaustSegmentedSectionPk",
+         "Test behaviour at Segmented Section exhaustion for PK"){
+  INITIALIZER(testSegmentedSectionPk);
+}
+
+TESTCASE("ExhaustSegmentedSectionIX",
+         "Test behaviour at Segmented Section exhaustion for PK"){
+  INITIALIZER(testSegmentedSectionIx);
+}
+
+NDBT_TESTSUITE_END(testLimits);
+
+int main(int argc, const char** argv){
+  ndb_init();
+  return testLimits.execute(argc, argv);
+}

=== modified file 'storage/ndb/test/ndbapi/testOIBasic.cpp'
--- a/storage/ndb/test/ndbapi/testOIBasic.cpp	2008-04-10 16:54:09 +0000
+++ b/storage/ndb/test/ndbapi/testOIBasic.cpp	2008-07-01 12:35:34 +0000
@@ -2127,8 +2127,8 @@
   CHARSET_INFO* cs = chs->m_cs;
   int k;
   if (!par.m_collsp) {
-    uchar x1[maxxmulsize * 8000];
-    uchar x2[maxxmulsize * 8000];
+    uchar x1[maxxmulsize * NDB_MAX_TUPLE_SIZE];
+    uchar x2[maxxmulsize * NDB_MAX_TUPLE_SIZE];
     // make strxfrm pad both to same length
     uint len = maxxmulsize * col.m_bytelength;
     int n1 = NdbSqlUtil::strnxfrm_bug7284(cs, x1, chs->m_xmul * len, buf1, len1);
@@ -2153,7 +2153,7 @@
 static void
 printstring(NdbOut& out, const uchar* str, uint len, bool showlen)
 {
-  char buf[4 * 8000];
+  char buf[4 * NDB_MAX_TUPLE_SIZE];
   char *p = buf;
   *p++ = '[';
   if (showlen) {

=== modified file 'storage/ndb/test/ndbapi/testPartitioning.cpp'
--- a/storage/ndb/test/ndbapi/testPartitioning.cpp	2008-02-19 15:00:29 +0000
+++ b/storage/ndb/test/ndbapi/testPartitioning.cpp	2008-07-01 12:35:34 +0000
@@ -394,7 +394,7 @@
   int result = NDBT_OK;
   for(int i = 0; i<records && result == NDBT_OK; i++)
   {
-    char buffer[8000];
+    char buffer[NDB_MAX_TUPLE_SIZE];
     char* start= buffer + (rand() & 7);
     char* pos= start;
     
@@ -474,7 +474,7 @@
   int result = NDBT_OK;
   for(int i = 0; i<records && result == NDBT_OK; i++)
   {
-    char buffer[8000];
+    char buffer[NDB_MAX_TUPLE_SIZE];
     char* start= buffer + (rand() & 7);
     char* pos= start;
     

=== modified file 'storage/ndb/test/run-test/daily-basic-tests.txt'
--- a/storage/ndb/test/run-test/daily-basic-tests.txt	2008-06-17 08:56:08 +0000
+++ b/storage/ndb/test/run-test/daily-basic-tests.txt	2008-07-01 12:35:34 +0000
@@ -1181,4 +1181,26 @@
 args: -n FailAddPartition T1 I3
 
 # EOF 2008-06-05
+
+# Test data buffering for TCKEYREQ
+max-time: 500
+cmd: testLimits
+args: -n ExhaustSegmentedSectionPk WIDE_2COL
+
+# Test data buffering for TCINDXREQ
+max-time: 500
+cmd: testLimits
+args: -n ExhaustSegmentedSectionIx WIDE_2COL_IX
+
+# Run some tests on max size / max num cols tables
+max-time: 500
+cmd: testBasic
+args: -n PkRead WIDE_MAXKEY_HUGO WIDE_MAXATTR_HUGO WIDE_MAXKEYMAXCOLS_HUGO WIDE_MINKEYMAXCOLS_HUGO
+
+max-time: 500
+cmd: testBasic
+args: -n PkUpdate WIDE_MAXKEY_HUGO WIDE_MAXATTR_HUGO WIDE_MAXKEYMAXCOLS_HUGO WIDE_MINKEYMAXCOLS_HUGO
+
+
+# EOF 2008-06-30
 # EOF

=== modified file 'storage/ndb/test/src/HugoCalculator.cpp'
--- a/storage/ndb/test/src/HugoCalculator.cpp	2007-03-15 06:10:23 +0000
+++ b/storage/ndb/test/src/HugoCalculator.cpp	2008-07-01 12:35:34 +0000
@@ -104,7 +104,11 @@
   else
     minlen = 64;
 
-  if (maxlen <= minlen)
+  if ((Uint32)maxlen <= minlen)
+    return maxlen;
+
+  /* Ensure coverage of maxlen */
+  if ((rvalue & 64) == 0)
     return maxlen;
 
   return minlen + (rvalue % (maxlen - minlen));
@@ -255,7 +259,7 @@
     if (i != m_updatesCol && id != m_idCol) {
       const NdbDictionary::Column* attr = m_tab.getColumn(i);      
       Uint32 len = attr->getSizeInBytes(), real_len;
-      char buf[8000];
+      char buf[NDB_MAX_TUPLE_SIZE];
       const char* res = calcValue(id, i, updates, buf, len, &real_len);
       if (res == NULL){
 	if (!pRow->attributeStore(i)->isNULL()){

=== modified file 'storage/ndb/test/src/HugoOperations.cpp'
--- a/storage/ndb/test/src/HugoOperations.cpp	2008-02-19 15:00:29 +0000
+++ b/storage/ndb/test/src/HugoOperations.cpp	2008-07-01 12:35:34 +0000
@@ -532,7 +532,7 @@
   }
   
   int len = attr->getSizeInBytes();
-  char buf[8000];
+  char buf[NDB_MAX_TUPLE_SIZE];
   memset(buf, 0, sizeof(buf));
   Uint32 real_len;
   const char * value = calc.calcValue(rowId, attrId, 0, buf, len, &real_len);
@@ -547,7 +547,7 @@
   const NdbDictionary::Column* attr = tab.getColumn(attrId);     
   
   int len = attr->getSizeInBytes();
-  char buf[8000];
+  char buf[NDB_MAX_TUPLE_SIZE];
   memset(buf, 0, sizeof(buf));
   Uint32 real_len;
   const char * value = calc.calcValue(rowId, attrId, 

=== modified file 'storage/ndb/test/src/NDBT_Tables.cpp'
--- a/storage/ndb/test/src/NDBT_Tables.cpp	2008-03-25 14:30:41 +0000
+++ b/storage/ndb/test/src/NDBT_Tables.cpp	2008-07-01 12:35:34 +0000
@@ -437,20 +437,6 @@
   &D1, &D2
 };
 
-struct NDBT_IndexList {
-  const char * m_table;
-  const char ** m_indexes;
-};
-
-static
-const
-NDBT_IndexList indexes[] = {
-  "I1", I1_Indexes, 
-  "I2", I2_Indexes, 
-  "I3", I3_Indexes,
-  0, 0
-};
-
 static
 const
 int numTestTables = sizeof(test_tables)/sizeof(NDBT_Table*);
@@ -757,6 +743,260 @@
 int numUtilTables = sizeof(util_tables)/sizeof(NDBT_Table*);
 
 
+/**
+ * Define other test tables that we may create
+ */
+
+/* WIDE_2COL
+ * Single var length key going up to max size of key
+ * Single var length attribute using remaining row space
+ */
+static 
+const
+NDBT_Attribute WIDE_2COL_ATTRIBS[] = {
+  /* Note that we can't have any index on this table as it
+   * has no space for the extra FRAGID the index requires!
+   */
+  NDBT_Attribute("KEY", NdbDictionary::Column::Longvarchar, 
+                 NDBT_Tables::MaxVarTypeKeyBytes, true), 
+  NDBT_Attribute("ATTR", NdbDictionary::Column::Longvarchar, 
+                 NDBT_Tables::MaxKeyMaxVarTypeAttrBytes, false)
+};
+
+
+static
+NDBT_Table WIDE_2COL("WIDE_2COL", sizeof(WIDE_2COL_ATTRIBS)/
+                     sizeof(NDBT_Attribute), WIDE_2COL_ATTRIBS);
+
+/* WIDE_2COL_IX
+ * Single var length key going up to max size of key
+ * Single var length attribute using most of remaining row space,
+ * but not all as we need space in the index for FragId
+ */
+static 
+const
+NDBT_Attribute WIDE_2COL_IX_ATTRIBS[] = {
+  NDBT_Attribute("KEY", NdbDictionary::Column::Longvarchar, 
+                 NDBT_Tables::MaxVarTypeKeyBytes, true), 
+  NDBT_Attribute("ATTR", NdbDictionary::Column::Longvarchar, 
+                 NDBT_Tables::MaxKeyMaxVarTypeAttrBytesIndex , false)
+};
+
+static
+NDBT_Table WIDE_2COL_IX("WIDE_2COL_IX", sizeof(WIDE_2COL_IX_ATTRIBS)/
+                        sizeof(NDBT_Attribute), WIDE_2COL_IX_ATTRIBS);
+
+static
+const char* WIDE_2COL_IX_Indexes[] = {
+  "UNIQUE", "ATTR", 0,
+  0};
+
+/* WIDE_MAXKEY_HUGO
+ * Single var length key going up to max size of key
+ * Var length attr going using up remaining space
+ * Two unsigned int columns required by Hugo tools
+ */
+static 
+const
+NDBT_Attribute WIDE_MAXKEY_HUGO_ATTRIBS[] = {
+  /* Note that we can't have any index on this table as it
+   * has no space for the extra FRAGID the index requires!
+   */
+  NDBT_Attribute("KEY", NdbDictionary::Column::Longvarchar, 
+                 NDBT_Tables::MaxVarTypeKeyBytes, true), 
+  NDBT_Attribute("ATTR", NdbDictionary::Column::Longvarchar, 
+                 NDBT_Tables::MaxKeyMaxVarTypeAttrBytes -
+                 NDBT_Tables::HugoOverheadBytes, false),
+  NDBT_Attribute("HUGOID", NdbDictionary::Column::Unsigned,
+                 1, false),
+  NDBT_Attribute("HUGOUPDATE", NdbDictionary::Column::Unsigned,
+                 1, false)
+};
+
+static
+NDBT_Table WIDE_MAXKEY_HUGO("WIDE_MAXKEY_HUGO", sizeof(WIDE_MAXKEY_HUGO_ATTRIBS)/
+                          sizeof(NDBT_Attribute), WIDE_MAXKEY_HUGO_ATTRIBS);
+
+/* WIDE_MAXATTR_HUGO
+ * Single unsigned int key
+ * Var length attr using up remaining space
+ * Two unsigned int columns required by Hugo tools
+ */
+static 
+const
+NDBT_Attribute WIDE_MAXATTR_HUGO_ATTRIBS[] = {
+  NDBT_Attribute("KEY", NdbDictionary::Column::Unsigned,
+                 1, true), 
+  NDBT_Attribute("ATTR", NdbDictionary::Column::Longvarchar, 
+                 NDBT_Tables::MinKeyMaxVarTypeAttrBytes -
+                 NDBT_Tables::HugoOverheadBytes, false),
+  NDBT_Attribute("HUGOID", NdbDictionary::Column::Unsigned,
+                 1, false),
+  NDBT_Attribute("HUGOUPDATE", NdbDictionary::Column::Unsigned,
+                 1, false)
+};
+
+static
+NDBT_Table WIDE_MAXATTR_HUGO("WIDE_MAXATTR_HUGO", sizeof(WIDE_MAXATTR_HUGO_ATTRIBS)/
+                             sizeof(NDBT_Attribute), WIDE_MAXATTR_HUGO_ATTRIBS);
+
+typedef NDBT_Table* (*TableGenerator)(const char* name);
+
+static NDBT_Table* WIDE_MAXKEYMAXCOLS_HUGO= NULL;
+
+static
+NDBT_Table* createMaxKeyMaxColsHugoTabDef(const char* name)
+{
+  if (WIDE_MAXKEYMAXCOLS_HUGO == NULL)
+  {
+    /* Create a wide table with the max num of keys
+     * and the max num of attrs
+     */
+    NdbDictionary::Column* attrs[NDB_MAX_ATTRIBUTES_IN_TABLE];
+    const int buffsize=100;
+    char namebuff[buffsize];
+    Uint32 attrNum=0;
+
+    /* Keys */
+    for (;attrNum < (NDB_MAX_ATTRIBUTES_IN_INDEX - 1); attrNum ++)
+    {
+      snprintf(namebuff, buffsize, "K%d", attrNum);
+      attrs[attrNum]= new NDBT_Attribute(namebuff,
+                                         NdbDictionary::Column::Unsigned,
+                                         1, true);
+    }
+    /* Last key uses remaining key space */
+    snprintf(namebuff, buffsize, "K%d", attrNum);
+    attrs[attrNum]= new NDBT_Attribute(namebuff,
+                                       NdbDictionary::Column::Char,
+                                       (NDB_MAX_KEYSIZE_IN_WORDS -
+                                        (NDB_MAX_ATTRIBUTES_IN_INDEX -1)) * 4,
+                                       true);
+
+    attrNum ++;
+
+    /* Attributes */
+    for (;attrNum < (NDB_MAX_ATTRIBUTES_IN_TABLE - 1); attrNum ++)
+    {
+      snprintf(namebuff, buffsize, "A%d", attrNum);
+      attrs[attrNum]= new NDBT_Attribute(namebuff,
+                                         NdbDictionary::Column::Unsigned,
+                                         1, false);
+    }
+
+    /* Last attr uses remaining attr space */
+    snprintf(namebuff, buffsize, "A%d", attrNum);
+    attrs[attrNum]= new NDBT_Attribute(namebuff,
+                                       NdbDictionary::Column::Char,
+                                       (NDB_MAX_TUPLE_SIZE_IN_WORDS -
+                                        NDB_MAX_KEYSIZE_IN_WORDS -
+                                        ((NDB_MAX_ATTRIBUTES_IN_TABLE -
+                                          NDB_MAX_ATTRIBUTES_IN_INDEX) - 1)) * 4,
+                                       false);
+    
+    WIDE_MAXKEYMAXCOLS_HUGO= new NDBT_Table(name, NDB_MAX_ATTRIBUTES_IN_TABLE,
+                                            attrs);
+
+    /* Free attributes, table will remain until program exit */
+    for (attrNum=0; attrNum < NDB_MAX_ATTRIBUTES_IN_TABLE; attrNum++)
+      delete attrs[attrNum];
+    
+  }
+
+  return WIDE_MAXKEYMAXCOLS_HUGO;
+}
+
+static NDBT_Table* WIDE_MINKEYMAXCOLS_HUGO= NULL;
+
+static
+NDBT_Table* createMinKeyMaxColsHugoTabDef(const char* name)
+{
+  if (WIDE_MINKEYMAXCOLS_HUGO == NULL)
+  {
+    /* Create a wide table with one key and the max number
+     * of attributes
+     */
+    NdbDictionary::Column* attrs[NDB_MAX_ATTRIBUTES_IN_TABLE];
+    const int buffsize=100;
+    char namebuff[buffsize];
+    Uint32 attrNum=0;
+    attrs[attrNum]= new NDBT_Attribute("K1",
+                                       NdbDictionary::Column::Unsigned,
+                                       1, true);
+    attrNum ++;
+
+    /* Attributes */
+    for (;attrNum < (NDB_MAX_ATTRIBUTES_IN_TABLE - 1); attrNum ++)
+    {
+      snprintf(namebuff, buffsize, "A%d", attrNum);
+      attrs[attrNum]= new NDBT_Attribute(namebuff,
+                                         NdbDictionary::Column::Unsigned,
+                                         1, false);
+    }
+    
+    /* Last attr uses remaining attr space */
+    snprintf(namebuff, buffsize, "A%d", attrNum);
+    attrs[attrNum]= new NDBT_Attribute(namebuff,
+                                       NdbDictionary::Column::Char,
+                                       (NDB_MAX_TUPLE_SIZE_IN_WORDS -
+                                        (NDB_MAX_ATTRIBUTES_IN_TABLE - 1)) * 4,
+                                       false);
+    
+    WIDE_MINKEYMAXCOLS_HUGO= new NDBT_Table(name, NDB_MAX_ATTRIBUTES_IN_TABLE,
+                                            attrs);
+
+    /* Free attributes, table will remain until program exit */
+    for (attrNum=0; attrNum < NDB_MAX_ATTRIBUTES_IN_TABLE; attrNum++)
+      delete attrs[attrNum];
+    
+
+  }
+
+  return WIDE_MINKEYMAXCOLS_HUGO;
+}
+
+// Define array with pointer to other test tables
+
+struct OtherTable
+{
+  const char* name;
+  NDBT_Table* tab;
+  TableGenerator tabGen;
+};
+
+static
+const
+OtherTable other_tables[]=
+{ 
+  {"WIDE_2COL", &WIDE_2COL, NULL},
+  {"WIDE_2COL_IX", &WIDE_2COL_IX, NULL},
+  {"WIDE_MAXKEY_HUGO", &WIDE_MAXKEY_HUGO, NULL},
+  {"WIDE_MAXATTR_HUGO", &WIDE_MAXATTR_HUGO, NULL},
+  {"WIDE_MAXKEYMAXCOLS_HUGO", NULL, createMaxKeyMaxColsHugoTabDef},
+  {"WIDE_MINKEYMAXCOLS_HUGO", NULL, createMinKeyMaxColsHugoTabDef}
+};
+
+static
+const
+int numOtherTables = sizeof(other_tables)/sizeof(OtherTable);
+
+
+/* Secondary indexes for our tables */
+struct NDBT_IndexList {
+  const char * m_table;
+  const char ** m_indexes;
+};
+
+static
+const
+NDBT_IndexList indexes[] = {
+  "I1", I1_Indexes, 
+  "I2", I2_Indexes, 
+  "I3", I3_Indexes,
+  "WIDE_2COL_IX", WIDE_2COL_IX_Indexes,
+  0, 0
+};
+
 const
 NdbDictionary::Table*
 NDBT_Tables::getTable(const char* _nam){
@@ -778,6 +1018,14 @@
       return util_tables[i];
     }
   }
+  for(i=0; i<numOtherTables; i++){
+    if (strcmp(other_tables[i].name, _nam) == 0){
+      return (other_tables[i].tab != NULL)? 
+        other_tables[i].tab :
+        (*other_tables[i].tabGen)(other_tables[i].name);
+    }
+  }
+
   // TPK_no tables
   // Dynamcially create table vith primary key size
   // set to no
@@ -1043,7 +1291,7 @@
 	
 	j++;
 	while(indexes[i].m_indexes[j] != 0){
-	  tmpIndx.addIndexColumn(indexes[i].m_indexes[j]);
+          tmpIndx.addIndexColumn(indexes[i].m_indexes[j]);
 	  j++;
 	}
 	j++;



