=== modified file 'mysql-test/suite/ndb/r/ndb_condition_pushdown.result'
--- a/mysql-test/suite/ndb/r/ndb_condition_pushdown.result	2008-05-22 16:26:30 +0000
+++ b/mysql-test/suite/ndb/r/ndb_condition_pushdown.result	2008-08-26 14:05:01 +0000
@@ -1962,5 +1962,124 @@
 2	Aberdeen
 show warnings;
 Level	Code	Message
+create table balerno (a int primary key, 
+b varchar(2000), 
+c varchar(2000)) engine=ndb;
+alter table balerno add index (b);
+show warnings;
+Level	Code	Message
+insert into balerno values (1, repeat('BA', 1000), repeat('CA', 1000));
+insert into balerno values (2, repeat('BB', 1000), repeat('CB', 1000));
+insert into balerno values (3, repeat('BC', 1000), repeat('CC', 1000));
+insert into balerno values (4, repeat('BD', 1000), repeat('CD', 1000));
+insert into balerno values (5, repeat('BE', 1000), repeat('CE', 1000));
+set engine_condition_pushdown = on;
+select a from balerno where b in (
+repeat('10', 1000),
+repeat('11', 1000),
+repeat('12', 1000),
+repeat('13', 1000),
+repeat('14', 1000),
+repeat('15', 1000),
+repeat('16', 1000),
+repeat('17', 1000),
+repeat('18', 1000),
+repeat('19', 1000),
+repeat('20', 1000),
+repeat('21', 1000),
+repeat('22', 1000),
+repeat('23', 1000),
+repeat('24', 1000),
+repeat('25', 1000),
+repeat('26', 1000),
+repeat('27', 1000),
+repeat('28', 1000),
+repeat('29', 1000),
+repeat('30', 1000),
+repeat('31', 1000),
+repeat('32', 1000),
+repeat('33', 1000),
+repeat('34', 1000),
+repeat('35', 1000),
+repeat('36', 1000),
+repeat('37', 1000),
+repeat('38', 1000),
+repeat('BA', 1000));
+a
+1
+show warnings;
+Level	Code	Message
+select a from balerno ignore index(b) where b in (
+repeat('10', 1000),
+repeat('11', 1000),
+repeat('12', 1000),
+repeat('13', 1000),
+repeat('14', 1000),
+repeat('15', 1000),
+repeat('16', 1000),
+repeat('17', 1000),
+repeat('18', 1000),
+repeat('19', 1000),
+repeat('20', 1000),
+repeat('21', 1000),
+repeat('22', 1000),
+repeat('23', 1000),
+repeat('24', 1000),
+repeat('25', 1000),
+repeat('26', 1000),
+repeat('27', 1000),
+repeat('28', 1000),
+repeat('29', 1000),
+repeat('30', 1000),
+repeat('31', 1000),
+repeat('32', 1000),
+repeat('33', 1000),
+repeat('34', 1000),
+repeat('35', 1000),
+repeat('36', 1000),
+repeat('37', 1000),
+repeat('38', 1000),
+repeat('BA', 1000));
+a
+1
+show warnings;
+Level	Code	Message
+set engine_condition_pushdown = off;
+select a from balerno where b in (
+repeat('10', 1000),
+repeat('11', 1000),
+repeat('12', 1000),
+repeat('13', 1000),
+repeat('14', 1000),
+repeat('15', 1000),
+repeat('16', 1000),
+repeat('17', 1000),
+repeat('18', 1000),
+repeat('19', 1000),
+repeat('20', 1000),
+repeat('21', 1000),
+repeat('22', 1000),
+repeat('23', 1000),
+repeat('24', 1000),
+repeat('25', 1000),
+repeat('26', 1000),
+repeat('27', 1000),
+repeat('28', 1000),
+repeat('29', 1000),
+repeat('30', 1000),
+repeat('31', 1000),
+repeat('32', 1000),
+repeat('33', 1000),
+repeat('34', 1000),
+repeat('35', 1000),
+repeat('36', 1000),
+repeat('37', 1000),
+repeat('38', 1000),
+repeat('BA', 1000));
+a
+1
+show warnings;
+Level	Code	Message
+drop table balerno;
 set engine_condition_pushdown = @old_ecpd;
 DROP TABLE t1,t2,t3,t4,t5;

=== modified file 'mysql-test/suite/ndb/t/ndb_condition_pushdown.test'
--- a/mysql-test/suite/ndb/t/ndb_condition_pushdown.test	2008-05-22 16:26:30 +0000
+++ b/mysql-test/suite/ndb/t/ndb_condition_pushdown.test	2008-08-26 14:05:01 +0000
@@ -2098,5 +2098,139 @@
 
 show warnings;
 
+# Test large SCANTABREQ
+create table balerno (a int primary key, 
+                      b varchar(2000), 
+                      c varchar(2000)) engine=ndb;
+
+alter table balerno add index (b);
+
+show warnings;
+
+insert into balerno values (1, repeat('BA', 1000), repeat('CA', 1000));
+insert into balerno values (2, repeat('BB', 1000), repeat('CB', 1000));
+insert into balerno values (3, repeat('BC', 1000), repeat('CC', 1000));
+insert into balerno values (4, repeat('BD', 1000), repeat('CD', 1000));
+insert into balerno values (5, repeat('BE', 1000), repeat('CE', 1000));
+
+# Large query with potential to generate large ATTRINFO from 
+# ScanFilter and large KEYINFO from index bounds with matching
+# condition at end of candidates.
+#
+# Use bounds + ScanFilter to select
+set engine_condition_pushdown = on;
+
+select a from balerno where b in (
+  repeat('10', 1000),
+  repeat('11', 1000),
+  repeat('12', 1000),
+  repeat('13', 1000),
+  repeat('14', 1000),
+  repeat('15', 1000),
+  repeat('16', 1000),
+  repeat('17', 1000),
+  repeat('18', 1000),
+  repeat('19', 1000),
+  repeat('20', 1000),
+  repeat('21', 1000),
+  repeat('22', 1000),
+  repeat('23', 1000),
+  repeat('24', 1000),
+  repeat('25', 1000),
+  repeat('26', 1000),
+  repeat('27', 1000),
+  repeat('28', 1000),
+  repeat('29', 1000),
+  repeat('30', 1000),
+  repeat('31', 1000),
+  repeat('32', 1000),
+  repeat('33', 1000),
+  repeat('34', 1000),
+  repeat('35', 1000),
+  repeat('36', 1000),
+  repeat('37', 1000),
+  repeat('38', 1000),
+  repeat('BA', 1000));
+
+show warnings;
+
+# Just use ScanFilter to select
+
+select a from balerno ignore index(b) where b in (
+  repeat('10', 1000),
+  repeat('11', 1000),
+  repeat('12', 1000),
+  repeat('13', 1000),
+  repeat('14', 1000),
+  repeat('15', 1000),
+  repeat('16', 1000),
+  repeat('17', 1000),
+  repeat('18', 1000),
+  repeat('19', 1000),
+  repeat('20', 1000),
+  repeat('21', 1000),
+  repeat('22', 1000),
+  repeat('23', 1000),
+  repeat('24', 1000),
+  repeat('25', 1000),
+  repeat('26', 1000),
+  repeat('27', 1000),
+  repeat('28', 1000),
+  repeat('29', 1000),
+  repeat('30', 1000),
+  repeat('31', 1000),
+  repeat('32', 1000),
+  repeat('33', 1000),
+  repeat('34', 1000),
+  repeat('35', 1000),
+  repeat('36', 1000),
+  repeat('37', 1000),
+  repeat('38', 1000),
+  repeat('BA', 1000));
+
+show warnings;
+
+set engine_condition_pushdown = off;
+
+# Just use Index bounds to select
+select a from balerno where b in (
+  repeat('10', 1000),
+  repeat('11', 1000),
+  repeat('12', 1000),
+  repeat('13', 1000),
+  repeat('14', 1000),
+  repeat('15', 1000),
+  repeat('16', 1000),
+  repeat('17', 1000),
+  repeat('18', 1000),
+  repeat('19', 1000),
+  repeat('20', 1000),
+  repeat('21', 1000),
+  repeat('22', 1000),
+  repeat('23', 1000),
+  repeat('24', 1000),
+  repeat('25', 1000),
+  repeat('26', 1000),
+  repeat('27', 1000),
+  repeat('28', 1000),
+  repeat('29', 1000),
+  repeat('30', 1000),
+  repeat('31', 1000),
+  repeat('32', 1000),
+  repeat('33', 1000),
+  repeat('34', 1000),
+  repeat('35', 1000),
+  repeat('36', 1000),
+  repeat('37', 1000),
+  repeat('38', 1000),
+  repeat('BA', 1000));
+
+show warnings;
+
+drop table balerno;
+
+
+
 set engine_condition_pushdown = @old_ecpd;
 DROP TABLE t1,t2,t3,t4,t5;
+

=== modified file 'storage/ndb/include/kernel/signaldata/ScanTab.hpp'
--- a/storage/ndb/include/kernel/signaldata/ScanTab.hpp	2007-10-11 14:14:29 +0000
+++ b/storage/ndb/include/kernel/signaldata/ScanTab.hpp	2008-08-26 14:05:01 +0000
@@ -48,6 +48,13 @@
   STATIC_CONST( StaticLength = 11 );
   STATIC_CONST( MaxTotalAttrInfo = 0xFFFF );
 
+  /**
+   * Long section nums
+   */
+  STATIC_CONST( ReceiverIdSectionNum = 0 );
+  STATIC_CONST( AttrInfoSectionNum = 1 );    /* Long SCANTABREQ only */
+  STATIC_CONST( KeyInfoSectionNum = 2 );     /* Long SCANTABREQ only */
+
 private:
 
   // Type definitions
@@ -56,7 +63,10 @@
    * DATA VARIABLES
    */
   UintR apiConnectPtr;        // DATA 0
-  UintR attrLenKeyLen;        // DATA 1
+  union {
+    UintR attrLenKeyLen;      // DATA 1 : Short SCANTABREQ (Versions < 6.4.0)
+    UintR spare;              // DATA 1 : Long SCANTABREQ 
+  };
   UintR requestInfo;          // DATA 2
   /*
     Table ID. Note that for a range scan of a table using an ordered index,

=== modified file 'storage/ndb/include/ndb_version.h.in'
--- a/storage/ndb/include/ndb_version.h.in	2008-08-07 11:52:50 +0000
+++ b/storage/ndb/include/ndb_version.h.in	2008-08-26 14:05:01 +0000
@@ -100,6 +100,7 @@
 #define NDBD_MICRO_GCP_63 NDB_MAKE_VERSION(6,3,2)
 #define NDBD_RAW_LCP MAKE_VERSION(6,3,11)
 #define NDBD_LONG_LQHKEYREQ MAKE_VERSION(6,4,0)
+#define NDBD_MAX_RECVBYTESIZE_32K MAKE_VERSION(6,3,17)
 
 
 static

=== modified file 'storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp'
--- a/storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp	2008-08-16 13:51:16 +0000
+++ b/storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp	2008-08-26 14:05:01 +0000
@@ -289,11 +289,11 @@
   int buildIndexBoundOldApi(int range_no);
   const IndexBound* getIndexBoundFromRecAttr(NdbRecAttr* recAttr);
   void releaseIndexBoundsOldApi();
-  int insertBOUNDS(Uint32 * data, Uint32 sz);
   int ndbrecord_insert_bound(const NdbRecord *key_record,
                              Uint32 column_index,
                              const char *row,
-                             Uint32 bound_type);
+                             Uint32 bound_type,
+                             Uint32*& firstWordOfBound);
 
   virtual int equal_impl(const NdbColumnImpl*, const char*);
   virtual NdbRecAttr* getValue_impl(const NdbColumnImpl*, char*);
@@ -314,8 +314,6 @@
   int compare_ndbrecord(const NdbReceiver *r1,
                         const NdbReceiver *r2) const;
   Uint32 m_sort_columns;
-  Uint32 m_this_bound_start;
-  Uint32 * m_first_bound_word;
 
   /* Number of IndexBounds for this scan (NdbRecord only) */
   Uint32 m_num_bounds;

=== modified file 'storage/ndb/include/ndbapi/NdbOperation.hpp'
--- a/storage/ndb/include/ndbapi/NdbOperation.hpp	2008-08-07 13:17:36 +0000
+++ b/storage/ndb/include/ndbapi/NdbOperation.hpp	2008-08-26 14:05:01 +0000
@@ -1138,6 +1138,9 @@
   virtual void	    release();			// Release all operations 
                                                 // connected to
 					      	// the operations object.      
+  void              postExecuteRelease();       // Release resources
+                                                // no longer needed after
+                                                // exceute 
   void		    setStartIndicator();
 
   /* Utility method to 'add' operation options to an NdbOperation
@@ -1198,28 +1201,14 @@
   Uint32 fillTcKeyReqHdr(TcKeyReq *tcKeyReq,
                          Uint32 connectPtr,
                          Uint64 transId);
-  int    allocKeyInfo(Uint32 connectPtr, Uint64 transId,
-                      Uint32 **dstPtr, Uint32 *remain);
-  int    allocAttrInfo(Uint32 connectPtr, Uint64 transId,
-                       Uint32 **dstPtr, Uint32 *remain);
-  int    insertKEYINFO_NdbRecord(Uint32 connectPtr,
-                                 Uint64 transId,
-                                 const char *value,
-                                 Uint32 size,
-                                 Uint32 **dstPtr,
-                                 Uint32 *remain);
-  int    insertATTRINFOHdr_NdbRecord(Uint32 connectPtr,
-                                     Uint64 transId,
-                                     Uint32 attrId,
-                                     Uint32 attrLen,
-                                     Uint32 **dstPtr,
-                                     Uint32 *remain);
-  int    insertATTRINFOData_NdbRecord(Uint32 connectPtr,
-                                      Uint64 transId,
-                                      const char *value,
-                                      Uint32 size,
-                                      Uint32 **dstPtr,
-                                      Uint32 *remain);
+  int    allocKeyInfo();
+  int    allocAttrInfo();
+  int    insertKEYINFO_NdbRecord(const char *value,
+                                 Uint32 byteSize);
+  int    insertATTRINFOHdr_NdbRecord(Uint32 attrId,
+                                     Uint32 attrLen);
+  int    insertATTRINFOData_NdbRecord(const char *value,
+                                      Uint32 size);
 
   int	 receiveTCKEYREF(NdbApiSignal*); 
 
@@ -1299,6 +1288,7 @@
   union {
     NdbApiSignal* theTCREQ;		// The TC[KEY/INDX]REQ signal object
     NdbApiSignal* theSCAN_TABREQ;
+    NdbApiSignal* theRequest;
   };
 
   NdbApiSignal*	   theFirstATTRINFO;	// The first ATTRINFO signal object 
@@ -1321,7 +1311,9 @@
   Uint32	    theNoOfSubroutines;
 
   Uint32*           theKEYINFOptr;       // Pointer to where to write KEYINFO
+  Uint32            keyInfoRemain;       // KeyInfo space in current signal
   Uint32*           theATTRINFOptr;      // Pointer to where to write ATTRINFO
+  Uint32            attrInfoRemain;      // AttrInfo space in current signal
 
   /* 
      The table object for the table to read or modify (for index operations,

=== modified file 'storage/ndb/include/transporter/TransporterDefinitions.hpp'
--- a/storage/ndb/include/transporter/TransporterDefinitions.hpp	2008-06-17 20:28:45 +0000
+++ b/storage/ndb/include/transporter/TransporterDefinitions.hpp	2008-08-26 14:05:01 +0000
@@ -41,11 +41,20 @@
 };
 
 /**
- * Protocol6 Header + 
- *  (optional signal id) + (optional checksum) + (signal data)
+ * Maximum message sizes
+ * ---------------------
+ * Maximum byte sizes for sent and received messages.
+ * Maximum received size increased in :
+ *   mysql-5.1-telco-6.3.17 from 16516 bytes to 32768
+ * Maximum send size increased in :
+ *   mysql-5.1-telco-6.4.0 from 16516 bytes to 32768
+ *
+ * Therefore mysql-5.1-telco-6.4.0 cannot safely communicate 
+ * with nodes at versions lower than mysql-5.1-telco-6.3.17 
+ * 
  */
-//const Uint32 MAX_MESSAGE_SIZE = (12+4+4+(4*25));
-const Uint32 MAX_MESSAGE_SIZE = (12+4+4+(4*25)+(3*4)+4*4096);
+const Uint32 MAX_RECV_MESSAGE_BYTESIZE = 32768;
+const Uint32 MAX_SEND_MESSAGE_BYTESIZE = 32768;
 
 /**
  * TransporterConfiguration

=== modified file 'storage/ndb/src/common/debugger/SignalLoggerManager.cpp'
--- a/storage/ndb/src/common/debugger/SignalLoggerManager.cpp	2008-07-25 05:48:32 +0000
+++ b/storage/ndb/src/common/debugger/SignalLoggerManager.cpp	2008-08-26 14:05:01 +0000
@@ -636,7 +636,6 @@
   Uint32 pos = 0;
   Uint32 chunksz = 0;
   fprintf(output, " size=%u\n", (unsigned)len);
-  ptr[i].sectionIter->reset();
   while (pos < len) {
     Uint32* data= ptr[i].sectionIter->getNextWords(chunksz);
     Uint32 i=0;

=== modified file 'storage/ndb/src/common/transporter/Packer.cpp'
--- a/storage/ndb/src/common/transporter/Packer.cpp	2008-06-17 20:28:45 +0000
+++ b/storage/ndb/src/common/transporter/Packer.cpp	2008-08-26 14:05:01 +0000
@@ -54,7 +54,7 @@
       const Uint16 messageLen32    = Protocol6::getMessageLength(word1);
       const Uint32 messageLenBytes = ((Uint32)messageLen32) << 2;
 
-      if(messageLen32 == 0 || messageLen32 > MAX_MESSAGE_SIZE){
+      if(messageLenBytes == 0 || messageLenBytes > MAX_RECV_MESSAGE_BYTESIZE){
         DEBUG("Message Size = " << messageLenBytes);
 	report_error(remoteNodeId, TE_INVALID_MESSAGE_LENGTH);
         return usedData;
@@ -136,7 +136,7 @@
       
       const Uint16 messageLen32    = Protocol6::getMessageLength(word1);
       const Uint32 messageLenBytes = ((Uint32)messageLen32) << 2;
-      if(messageLen32 == 0 || messageLen32 > MAX_MESSAGE_SIZE){
+      if(messageLenBytes == 0 || messageLenBytes > MAX_RECV_MESSAGE_BYTESIZE){
 	DEBUG("Message Size = " << messageLenBytes);
 	report_error(remoteNodeId, TE_INVALID_MESSAGE_LENGTH);
         return usedData;
@@ -234,7 +234,9 @@
       
       const Uint16 messageLen32    = Protocol6::getMessageLength(word1);
       
-      if(messageLen32 == 0 || messageLen32 > MAX_MESSAGE_SIZE){
+      if(messageLen32 == 0 || 
+         messageLen32 > (MAX_RECV_MESSAGE_BYTESIZE >> 2))
+      {
         DEBUG("Message Size(words) = " << messageLen32);
 	report_error(remoteNodeId, TE_INVALID_MESSAGE_LENGTH);
         return readPtr;
@@ -304,7 +306,9 @@
 #endif
       
       const Uint16 messageLen32    = Protocol6::getMessageLength(word1);
-      if(messageLen32 == 0 || messageLen32 > MAX_MESSAGE_SIZE){
+      if(messageLen32 == 0 || 
+         messageLen32 > (MAX_RECV_MESSAGE_BYTESIZE >> 2))
+      {
 	DEBUG("Message Size(words) = " << messageLen32);
 	report_error(remoteNodeId, TE_INVALID_MESSAGE_LENGTH);
         return readPtr;
@@ -400,13 +404,12 @@
   /* Use the section iterator to obtain the words in this section */
   Uint32 remain= ptr.sz;
 
-  ptr.sectionIter->reset();
-
   while (remain > 0)
   {
     Uint32 len= 0;
     Uint32* next= ptr.sectionIter->getNextWords(len);
 
+    assert(len <= remain);
     assert(next != NULL);
 
     memcpy(insertPtr, next, 4 * len);

=== modified file 'storage/ndb/src/common/transporter/SHM_Transporter.cpp'
--- a/storage/ndb/src/common/transporter/SHM_Transporter.cpp	2008-05-29 15:06:11 +0000
+++ b/storage/ndb/src/common/transporter/SHM_Transporter.cpp	2008-08-26 14:05:01 +0000
@@ -42,7 +42,8 @@
   Transporter(t_reg, tt_SHM_TRANSPORTER,
 	      lHostName, rHostName, r_port, isMgmConnection_arg,
 	      lNodeId, rNodeId, serverNodeId,
-	      0, false, checksum, signalId, 4096 + MAX_MESSAGE_SIZE),
+	      0, false, checksum, signalId, 
+              4096 + MAX_SEND_MESSAGE_BYTESIZE),
   shmKey(_shmKey),
   shmSize(_shmSize)
 {
@@ -80,7 +81,8 @@
   sharedSize += 28; //SHM_Reader::getSharedSize();
   sharedSize += 28; //SHM_Writer::getSharedSize();
 
-  const Uint32 slack = MAX_MESSAGE_SIZE;
+  const Uint32 slack = MAX(MAX_RECV_MESSAGE_BYTESIZE,
+                           MAX_SEND_MESSAGE_BYTESIZE);
 
   /**
    *  NOTE: There is 7th shared variable in Win2k (sharedCountAttached).

=== modified file 'storage/ndb/src/common/transporter/SendBuffer.cpp'
--- a/storage/ndb/src/common/transporter/SendBuffer.cpp	2006-12-23 19:20:40 +0000
+++ b/storage/ndb/src/common/transporter/SendBuffer.cpp	2008-08-26 14:05:01 +0000
@@ -19,8 +19,8 @@
 SendBuffer::SendBuffer(Uint32 bufSize) {
 
   sizeOfBuffer = bufSize;
-  if(sizeOfBuffer < MAX_MESSAGE_SIZE)
-    sizeOfBuffer = 2 * MAX_MESSAGE_SIZE; 
+  if(sizeOfBuffer < MAX_SEND_MESSAGE_BYTESIZE)
+    sizeOfBuffer = 2 * MAX_SEND_MESSAGE_BYTESIZE; 
   startOfBuffer = NULL;
 
   // Initalise pointers 

=== modified file 'storage/ndb/src/common/transporter/TCP_Transporter.cpp'
--- a/storage/ndb/src/common/transporter/TCP_Transporter.cpp	2008-05-29 15:06:11 +0000
+++ b/storage/ndb/src/common/transporter/TCP_Transporter.cpp	2008-08-26 14:05:01 +0000
@@ -146,11 +146,11 @@
   // Let it be the maximum size we receive plus 8 kB for any earlier received
   // incomplete messages (slack)
   Uint32 recBufSize = maxReceiveSize;
-  if(recBufSize < MAX_MESSAGE_SIZE){
-    recBufSize = MAX_MESSAGE_SIZE;
+  if(recBufSize < MAX_RECV_MESSAGE_BYTESIZE){
+    recBufSize = MAX_RECV_MESSAGE_BYTESIZE;
   }
   
-  if(!receiveBuffer.init(recBufSize+MAX_MESSAGE_SIZE)){
+  if(!receiveBuffer.init(recBufSize+MAX_RECV_MESSAGE_BYTESIZE)){
     return false;
   }
   

=== modified file 'storage/ndb/src/common/transporter/TransporterRegistry.cpp'
--- a/storage/ndb/src/common/transporter/TransporterRegistry.cpp	2008-08-13 20:28:10 +0000
+++ b/storage/ndb/src/common/transporter/TransporterRegistry.cpp	2008-08-26 14:05:01 +0000
@@ -593,7 +593,7 @@
 	 
     if(t->isConnected()){
       Uint32 lenBytes = t->m_packer.getMessageLength(signalHeader, ptr);
-      if(lenBytes <= MAX_MESSAGE_SIZE){
+      if(lenBytes <= MAX_SEND_MESSAGE_BYTESIZE){
 	Uint32 * insertPtr = getWritePtr(sendHandle, nodeId, lenBytes, prio);
 	if(insertPtr != 0){
 	  t->m_packer.pack(insertPtr, prio, signalHeader, signalData, ptr);
@@ -666,7 +666,7 @@
     
     if(t->isConnected()){
       Uint32 lenBytes = t->m_packer.getMessageLength(signalHeader, ptr);
-      if(lenBytes <= MAX_MESSAGE_SIZE){
+      if(lenBytes <= MAX_SEND_MESSAGE_BYTESIZE){
 	Uint32 * insertPtr = getWritePtr(sendHandle, nodeId, lenBytes, prio);
 	if(insertPtr != 0){
 	  t->m_packer.pack(insertPtr, prio, signalHeader, signalData, thePool, ptr);
@@ -739,7 +739,7 @@
 	 
     if(t->isConnected()){
       Uint32 lenBytes = t->m_packer.getMessageLength(signalHeader, ptr);
-      if(lenBytes <= MAX_MESSAGE_SIZE){
+      if(lenBytes <= MAX_SEND_MESSAGE_BYTESIZE){
         Uint32 * insertPtr = getWritePtr(sendHandle, nodeId, lenBytes, prio);
         if(insertPtr != 0){
           t->m_packer.pack(insertPtr, prio, signalHeader, signalData, ptr);

=== modified file 'storage/ndb/src/common/util/version.c'
--- a/storage/ndb/src/common/util/version.c	2008-05-09 10:12:16 +0000
+++ b/storage/ndb/src/common/util/version.c	2008-08-26 14:05:01 +0000
@@ -110,6 +110,10 @@
 
 #ifndef TEST_VERSION
 struct NdbUpGradeCompatible ndbCompatibleTable_full[] = {
+  /* Can only upgrade to 6.4.X from versions >= 6.3.17 due to change
+   * in Transporter maximum sent message size
+   */
+  { MAKE_VERSION(6,4,NDB_VERSION_BUILD), NDBD_MAX_RECVBYTESIZE_32K, UG_Range },
   { MAKE_VERSION(6,3,NDB_VERSION_BUILD), MAKE_VERSION(6,2,1), UG_Range },
 
   { MAKE_VERSION(6,2,NDB_VERSION_BUILD), MAKE_VERSION(6,2,1), UG_Range },

=== modified file 'storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp'
--- a/storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp	2008-08-11 12:48:03 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp	2008-08-26 14:05:01 +0000
@@ -43,28 +43,21 @@
  */
 #define Z8NIL 255
 #define ZAPI_CONNECT_FILESIZE 20
-#define ZATTRBUF_FILESIZE 4000
 #define ZCLOSED 2
 #define ZCOMMITING 0			 /* VALUE FOR TRANSTATUS        */
 #define ZCOMMIT_SETUP 2
 #define ZCONTINUE_ABORT_080 4
-#define ZDATABUF_FILESIZE 4000
 #define ZGCP_FILESIZE 10
-#define ZINBUF_DATA_LEN 24	 /* POSITION OF 'DATA LENGHT'-VARIABLE. */
-#define ZINBUF_NEXT 27 		 /* POSITION OF 'NEXT'-VARIABLE.        */
-#define ZINBUF_PREV 26 		 /* POSITION OF 'PREVIOUS'-VARIABLE.    */
 #define ZINTSPH1 1
 #define ZINTSPH2 2
 #define ZINTSPH3 3
 #define ZINTSPH6 6
 #define ZLASTPHASE 255
-#define ZMAX_DATA_IN_LQHKEYREQ 12
 #define ZNODEBUF_FILESIZE 2000
 #define ZNR_OF_SEIZE 10
 #define ZSCANREC_FILE_SIZE 100
 #define ZSCAN_FRAGREC_FILE_SIZE 400
 #define ZSCAN_OPREC_FILE_SIZE 400
-#define ZSEND_ATTRINFO 0
 #define ZSPH1 1
 #define ZTABREC_FILESIZE 16
 #define ZTAKE_OVER_ACTIVE 1
@@ -880,89 +873,53 @@
   //---------------------------------------------------------------------------
 
   struct CacheRecord {
-    //---------------------------------------------------
-    // First 16 byte cache line. Variables used by
-    // ATTRINFO processing.
-    //---------------------------------------------------
-    UintR  firstAttrbuf;      /* POINTER TO LINKED LIST OF ATTRIBUTE BUFFERS */
-    UintR  lastAttrbuf;       /* POINTER TO LINKED LIST OF ATTRIBUTE BUFFERS */
-    UintR  currReclenAi;
-    Uint16 attrlength;        /* ATTRIBUTE INFORMATION LENGTH                */
-    Uint16 save1;
-    
-    //---------------------------------------------------
-    // Second 16 byte cache line. Variables initiated by
-    // TCKEYREQ and used in LQHKEYREQ.
-    //---------------------------------------------------
-    UintR  attrinfo15[4];
-    
-    //---------------------------------------------------
-    // Third 16 byte cache line. Variables initiated by
-    // TCKEYREQ and used in LQHKEYREQ.
-    //---------------------------------------------------
-    UintR  attrinfo0;
-    UintR  schemaVersion;/* SCHEMA VERSION USED IN TRANSACTION         */
-    UintR  tableref;     /* POINTER TO THE TABLE IN WHICH THE FRAGMENT EXISTS*/
-    Uint16 apiVersionNo;
-    Uint16 keylen;       /* KEY LENGTH SENT BY REQUEST SIGNAL                */
-    
-    //---------------------------------------------------
-    // Fourth 16 byte cache line. Variables initiated by
-    // TCKEYREQ and used in LQHKEYREQ.
-    //---------------------------------------------------
-    UintR  keydata[4];   /* RECEIVES FIRST 16 BYTES OF TUPLE KEY         */
-    
-    //---------------------------------------------------
-    // First 16 byte cache line in second 64 byte cache
-    // line. Diverse use.
-    //---------------------------------------------------
-    UintR  fragmentid;   /* THE COMPUTED FRAGMENT ID                     */
-    UintR  hashValue;    /* THE HASH VALUE USED TO LOCATE FRAGMENT       */
-    
-    Uint8  distributionKeyIndicator;
-    Uint8  m_special_hash; // collation or distribution key
-    Uint8  m_no_disk_flag;
-    Uint8  lenAiInTckeyreq;  /* LENGTH OF ATTRIBUTE INFORMATION IN TCKEYREQ */
-
-    Uint8  fragmentDistributionKey;  /* DIH generation no */
-
-    /**
-     * EXECUTION MODE OF OPERATION                    
-     * 0 = NORMAL EXECUTION, 1 = INTERPRETED EXECUTION
-     */
-    Uint8  opExec;     
-
-    /* Use of Long signals */
-    Uint8  isLongTcKeyReq;   /* Incoming TcKeyReq used long signal */
-    Uint8  useLongLqhKeyReq; /* Outgoing LqhKeyReq should be long */
-
-    //---------------------------------------------------
-    // Second 16 byte cache line in second 64 byte cache
-    // line. Diverse use.
-    //---------------------------------------------------
-    UintR  distributionKey;
-    UintR  nextCacheRec;
-    UintR  unused3;
-    Uint32 scanInfo;
-    
-    //---------------------------------------------------
-    // Third 16 byte cache line in second 64
-    // byte cache line. Diverse use.
-    //---------------------------------------------------
-    Uint32 unused4;
-    Uint32 scanTakeOverInd;
-    UintR  firstKeybuf;   /* POINTER THE LINKED LIST OF KEY BUFFERS       */
-    UintR  lastKeybuf;    /* VARIABLE POINTING TO THE LAST KEY BUFFER     */
-
-    //---------------------------------------------------
-    // Fourth 16 byte cache line in second 64
-    // byte cache line. Diverse use.
-    // Second 8 bytes not used currently
-    //---------------------------------------------------
-    /* I-values for KeyInfo and AttrInfo sections */ 
-    Uint32 keyInfoSectionI;
-    Uint32 attrInfoSectionI;
-    UintR  packedCacheVar[2];
+    /* Fields used by TCKEYREQ/TCINDXREQ/SCANTABREQ */
+      Uint32 keyInfoSectionI;   /* KeyInfo section I-val */
+      Uint32 attrInfoSectionI;  /* AttrInfo section I-val */
+
+      // TODO : Consider using section length + other vars for this 
+      UintR  currReclenAi;      /* AttrInfo words received so far */
+      Uint16 attrlength;        /* Total AttrInfo length */
+      Uint16 save1;             /* KeyInfo words received so far */
+      Uint16 keylen;            /* KEY LENGTH SENT BY REQUEST SIGNAL */
+    
+      /* Distribution information */
+      // TODO : Consider placing this info into other records
+      Uint8  distributionKeyIndicator;
+      UintR  distributionKey;
+    /* End of fields used by TCKEYREQ/TCINDXREQ/SCANTABREQ */
+    
+
+    /* TCKEYREQ/TCINDXREQ only fields */
+      UintR  schemaVersion;/* SCHEMA VERSION USED IN TRANSACTION         */
+      UintR  tableref;     /* POINTER TO THE TABLE IN WHICH THE FRAGMENT EXISTS*/
+      Uint16 apiVersionNo;
+    
+      UintR  fragmentid;   /* THE COMPUTED FRAGMENT ID                     */
+      UintR  hashValue;    /* THE HASH VALUE USED TO LOCATE FRAGMENT       */
+    
+      Uint8  m_special_hash; // collation or distribution key
+      Uint8  m_no_disk_flag; 
+      Uint8  lenAiInTckeyreq;  /* LENGTH OF ATTRIBUTE INFORMATION IN TCKEYREQ */
+    
+      Uint8  fragmentDistributionKey;  /* DIH generation no */
+    
+      /**
+       * EXECUTION MODE OF OPERATION                    
+       * 0 = NORMAL EXECUTION, 1 = INTERPRETED EXECUTION
+       */
+      Uint8  opExec;     
+    
+      /* Use of Long signals */
+      Uint8  isLongTcKeyReq;   /* Incoming TcKeyReq used long signal */
+      Uint8  useLongLqhKeyReq; /* Outgoing LqhKeyReq should be long */
+    
+      UintR  nextCacheRec;
+      Uint32 scanInfo;
+    
+      Uint32 scanTakeOverInd;
+    /* End of TCKEYREQ/TCINDXREQ only fields */
+
   };
   
   typedef Ptr<CacheRecord> CacheRecordPtr;
@@ -1267,38 +1224,6 @@
   };   
   typedef Ptr<ScanRecord> ScanRecordPtr;
   
-  /* **********************************************************************$ */
-  /* ******$                        DATA BUFFER                      ******$ */
-  /*                                                                         */
-  /*       THIS BUFFER IS USED AS A GENERAL DATA STORAGE.                    */
-  /* **********************************************************************$ */
-  struct DatabufRecord {
-    UintR data[4];
-    /* 4 * 1 WORD = 4 WORD   */
-    UintR nextDatabuf;
-  }; /* p2c: size = 20 bytes */
-  
-  typedef Ptr<DatabufRecord> DatabufRecordPtr;
-
-  /* **********************************************************************$ */
-  /* ******$                 ATTRIBUTE INFORMATION RECORD            ******$ */
-  /*
-   * CAN CONTAIN ONE (1) ATTRINFO SIGNAL. ONE SIGNAL CONTAINS 24 ATTR.      
-   * INFO WORDS. BUT 32 ELEMENTS ARE USED TO MAKE PLEX HAPPY.
-   * SOME OF THE ELEMENTS ARE USED TO THE FOLLOWING THINGS:                 
-   * DATA LENGHT IN THIS RECORD IS STORED IN THE ELEMENT INDEXED BY          
-   * ZINBUF_DATA_LEN.                                                         
-   * NEXT FREE ATTRBUF IS POINTED OUT BY THE ELEMENT INDEXED BY               
-   * PREVIOUS ATTRBUF IS POINTED OUT BY THE ELEMENT INDEXED BY ZINBUF_PREV     
-   * (NOT USED YET).                                                          
-   * NEXT ATTRBUF IS POINTED OUT BY THE ELEMENT INDEXED BY ZINBUF_NEXT.   */
-  /* ******************************************************************** */
-  struct AttrbufRecord {
-    UintR attrbuf[32];
-  }; /* p2c: size = 128 bytes */
-  
-  typedef Ptr<AttrbufRecord> AttrbufRecordPtr;
-
   /*************************************************************************>*/
   /*                     GLOBAL CHECKPOINT INFORMATION RECORD                */
   /*                                                                         */
@@ -1485,7 +1410,9 @@
   void initScanTcrec(Signal* signal);
   void initScanrec(ScanRecordPtr,  const class ScanTabReq*,
 		   const UintR scanParallel, 
-		   const UintR noOprecPerFrag);
+		   const UintR noOprecPerFrag,
+                   const Uint32 aiLength,
+                   const Uint32 keyLength);
   void initScanfragrec(Signal* signal);
   void releaseScanResources(Signal*, ScanRecordPtr, bool not_started = false);
   ScanRecordPtr seizeScanrec(Signal* signal);
@@ -1509,8 +1436,6 @@
   void initApiConnectRec(Signal* signal, 
 			 ApiConnectRecord * const regApiPtr,
 			 bool releaseIndexOperations = false);
-  void initattrbuf(Signal* signal);
-  void initdatabuf(Signal* signal);
   void initgcp(Signal* signal);
   void inithost(Signal* signal);
   void initialiseScanrec(Signal* signal);
@@ -1520,7 +1445,6 @@
   void initialiseTcConnect(Signal* signal);
   void linkApiToGcp(Ptr<GcpRecord>, Ptr<ApiConnectRecord>);
   void linkGciInGcilist(Ptr<GcpRecord>);
-  void linkKeybuf(Signal* signal);
   void linkTcInConnectionlist(Signal* signal);
   void releaseAbortResources(Signal* signal);
   void releaseApiCon(Signal* signal, UintR aApiConnectPtr);
@@ -1533,23 +1457,18 @@
   void releaseTcCon();
   void releaseTcConnectFail(Signal* signal);
   void releaseTransResources(Signal* signal);
-  void saveAttrbuf(Signal* signal);
   void seizeApiConnect(Signal* signal);
   void seizeApiConnectCopy(Signal* signal);
   void seizeApiConnectFail(Signal* signal);
-  void seizeDatabuf(Signal* signal);
   void seizeGcp(Ptr<GcpRecord> & dst, Uint64 gci);
   void seizeTcConnect(Signal* signal);
   void seizeTcConnectFail(Signal* signal);
   Ptr<ApiConnectRecord> sendApiCommit(Signal* signal);
-  void sendAttrinfo(Signal* signal,
-                    UintR TattrinfoPtr,
-                    AttrbufRecord * const regAttrPtr,
-                    UintR TBref);
   bool sendAttrInfoTrain(Signal* signal,
                          UintR TBRef,
+                         Uint32 connectPtr,
                          Uint32 offset,
-                         SegmentedSectionPtr& section);
+                         Uint32 attrInfoIVal);
   void sendContinueTimeOutControl(Signal* signal, Uint32 TapiConPtr);
   void sendlqhkeyreq(Signal* signal, 
                      BlockReference TBRef);
@@ -1643,13 +1562,11 @@
   void diFcountReqLab(Signal* signal, ScanRecordPtr);
   void signalErrorRefuseLab(Signal* signal);
   void abort080Lab(Signal* signal);
-  void packKeyData000Lab(Signal* signal, 
-                         BlockReference TBRef, 
-                         Uint32 len);
-  void packKeyDataFromSection(Signal* signal,
-                              BlockReference TBRef,
-                              Uint32 offset,
-                              SegmentedSectionPtr& keyInfoSection);
+  void sendKeyInfoTrain(Signal* signal,
+                        BlockReference TBRef,
+                        Uint32 connectPtr,
+                        Uint32 offset,
+                        Uint32 keyInfoIVal);
   void abortScanLab(Signal* signal, ScanRecordPtr, Uint32 errCode, 
 		    bool not_started = false);
   void sendAbortedAfterTimeout(Signal* signal, int Tcheck);
@@ -1672,8 +1589,8 @@
   void releaseAtErrorLab(Signal* signal);
   void seizeDatabuferrorLab(Signal* signal);
   void appendToSectionErrorLab(Signal* signal);
+  void scanKeyinfoLab(Signal* signal);
   void scanAttrinfoLab(Signal* signal, UintR Tlen);
-  void seizeAttrbuferrorLab(Signal* signal);
   void attrinfoDihReceivedLab(Signal* signal);
   void aiErrorLab(Signal* signal);
   void scanReleaseResourcesLab(Signal* signal);
@@ -1732,11 +1649,6 @@
   CacheRecordPtr cachePtr;
   UintR ccacheFilesize;
 
-  // TODO : Remove when SCANTABREQ uses SegmentedSection
-  AttrbufRecord *attrbufRecord;
-  AttrbufRecordPtr attrbufptr;
-  UintR cattrbufFilesize;
-
   HostRecord *hostRecord;
   HostRecordPtr hostptr;
   UintR chostFilesize;
@@ -1797,7 +1709,6 @@
   Uint16 cownNodeid;
   Uint16 terrorCode;
 
-  UintR cfirstfreeAttrbuf;
   UintR cfirstfreeTcConnect;
   UintR cfirstfreeApiConnectCopy;
   UintR cfirstfreeCacheRec;
@@ -1811,7 +1722,6 @@
   UintR cfirstfreeApiConnectFail;
   UintR cfirstfreeApiConnect;
 
-  UintR cfirstfreeDatabuf;
   BlockReference cdihblockref;
   BlockReference cownref;                   /* OWN BLOCK REFERENCE */
 
@@ -1824,7 +1734,6 @@
   ScanFragRecPtr scanFragptr;
 
   UintR cscanFragrecFileSize;
-  UintR cdatabufFilesize;
 
   BlockReference cdictblockref;
   BlockReference cerrorBlockref;
@@ -1856,11 +1765,6 @@
   UintR capiConnectClosing[MAX_NODES];
   UintR con_lineNodes;
 
-  // TODO : Remove when ScanTabReq uses Segmented Sections
-  DatabufRecord *databufRecord;
-  DatabufRecordPtr databufptr;
-  DatabufRecordPtr tmpDatabufptr;
-
   UintR treqinfo;
   UintR ttransid1;
   UintR ttransid2;

=== modified file 'storage/ndb/src/kernel/blocks/dbtc/DbtcInit.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtc/DbtcInit.cpp	2008-08-15 11:01:41 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtc/DbtcInit.cpp	2008-08-26 14:05:01 +0000
@@ -25,11 +25,9 @@
 
 void Dbtc::initData() 
 {
-  cattrbufFilesize = ZATTRBUF_FILESIZE;
   capiConnectFilesize = ZAPI_CONNECT_FILESIZE;
   ccacheFilesize = ZAPI_CONNECT_FILESIZE;
   chostFilesize = MAX_NODES;
-  cdatabufFilesize = ZDATABUF_FILESIZE;
   cgcpFilesize = ZGCP_FILESIZE;
   cscanrecFileSize = ZSCANREC_FILE_SIZE;
   cscanFragrecFileSize = ZSCAN_FRAGREC_FILE_SIZE;
@@ -141,14 +139,6 @@
 
   indexOps.release();
   
-  databufRecord = (DatabufRecord*)allocRecord("DatabufRecord",
-					      sizeof(DatabufRecord),
-					      cdatabufFilesize);
-
-  attrbufRecord = (AttrbufRecord*)allocRecord("AttrbufRecord",
-					      sizeof(AttrbufRecord),
-					      cattrbufFilesize);
-
   gcpRecord = (GcpRecord*)allocRecord("GcpRecord",
 				      sizeof(GcpRecord), 
 				      cgcpFilesize);
@@ -286,8 +276,6 @@
   hostRecord = 0;
   tableRecord = 0;
   scanRecord = 0;
-  databufRecord = 0;
-  attrbufRecord = 0;
   gcpRecord = 0;
   tcFailRecord = 0;
   c_apiConTimer = 0;
@@ -300,12 +288,9 @@
     void* tmp[] = { &apiConnectptr, 
 		    &tcConnectptr,
 		    &cachePtr,
-		    &attrbufptr,
 		    &hostptr,
 		    &timeOutptr,
-		    &scanFragptr,
-		    &databufptr,
-		    &tmpDatabufptr }; 
+		    &scanFragptr }; 
     init_globals_list(tmp, sizeof(tmp)/sizeof(tmp[0]));
   }
 #endif
@@ -315,8 +300,6 @@
   hostRecord = 0;
   tableRecord = 0;
   scanRecord = 0;
-  databufRecord = 0;
-  attrbufRecord = 0;
   gcpRecord = 0;
   tcFailRecord = 0;
   c_apiConTimer = 0;
@@ -352,14 +335,6 @@
 		sizeof(ScanRecord),
 		cscanrecFileSize);
     
-  deallocRecord((void **)&databufRecord, "DatabufRecord",
-		sizeof(DatabufRecord),
-		cdatabufFilesize);
-  
-  deallocRecord((void **)&attrbufRecord, "AttrbufRecord",
-		sizeof(AttrbufRecord),
-		cattrbufFilesize);
-  
   deallocRecord((void **)&gcpRecord, "GcpRecord",
 		sizeof(GcpRecord), 
 		cgcpFilesize);

=== modified file 'storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp	2008-08-21 22:18:36 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp	2008-08-26 14:05:01 +0000
@@ -1822,125 +1822,45 @@
     tckeyreq020Lab(signal);
     return;
   case OS_WAIT_SCAN:
-    break;
+    jam();
+    scanKeyinfoLab(signal);
+    return;
   default:
     jam();
     terrorCode = ZSTATE_ERROR;
     abortErrorLab(signal);
     return;
   }//switch
-
-  UintR TdataPos = 0;
-  UintR TkeyLen = regCachePtr->keylen;
-  UintR Tlen = regCachePtr->save1;
-
-  do {
-    if (cfirstfreeDatabuf == RNIL) {
-      jam();
-      seizeDatabuferrorLab(signal);
-      return;
-    }//if
-    linkKeybuf(signal);
-    arrGuard(TdataPos, 19);
-    databufptr.p->data[0] = signal->theData[TdataPos + 3];
-    databufptr.p->data[1] = signal->theData[TdataPos + 4];
-    databufptr.p->data[2] = signal->theData[TdataPos + 5];
-    databufptr.p->data[3] = signal->theData[TdataPos + 6];
-    Tlen = Tlen + 4;
-    TdataPos = TdataPos + 4;
-    if (Tlen < TkeyLen) {
-      jam();
-      if (TdataPos >= tmaxData) {
-        jam();
-	/*----------------------------------------------------*/
-	/** EXIT AND WAIT FOR SIGNAL KEYINFO OR KEYINFO9     **/
-	/** WHEN EITHER OF THE SIGNALS IS RECEIVED A JUMP    **/
-	/** TO LABEL "KEYINFO_LABEL" IS DONE. THEN THE       **/
-	/** PROGRAM RETURNS TO LABEL TCKEYREQ020             **/
-	/*----------------------------------------------------*/
-        setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__);
-        regCachePtr->save1 = Tlen;
-        return;
-      }//if
-    } else {
-      jam();
-      return;
-    }//if
-  } while (1);
-  return;
 }//Dbtc::execKEYINFO()
 
-/*---------------------------------------------------------------------------*/
-/*                                                                           */
-/* MORE THAN FOUR WORDS OF KEY DATA. WE NEED TO PACK THIS IN KEYINFO SIGNALS.*/
-/* WE WILL ALWAYS PACK 4 WORDS AT A TIME.                                    */
-/*---------------------------------------------------------------------------*/
-void Dbtc::packKeyData000Lab(Signal* signal,
-                             BlockReference TBRef,
-			     Uint32 totalLen) 
-{
-  CacheRecord * const regCachePtr = cachePtr.p;
-
-  jam();
-  Uint32 len = 0;
-  databufptr.i = regCachePtr->firstKeybuf;
-  signal->theData[0] = tcConnectptr.i;
-  signal->theData[1] = apiConnectptr.p->transid[0];
-  signal->theData[2] = apiConnectptr.p->transid[1];
-  Uint32 * dst = signal->theData+3;
-  ptrCheckGuard(databufptr, cdatabufFilesize, databufRecord);
-  
-  do {
-    jam();
-    databufptr.i = databufptr.p->nextDatabuf;
-    dst[len + 0] = databufptr.p->data[0];
-    dst[len + 1] = databufptr.p->data[1];
-    dst[len + 2] = databufptr.p->data[2];
-    dst[len + 3] = databufptr.p->data[3];
-    len += 4;
-    if (totalLen <= 4) {
-      jam();
-      /*---------------------------------------------------------------------*/
-      /*       LAST PACK OF KEY DATA HAVE BEEN SENT                          */
-      /*---------------------------------------------------------------------*/
-      /*       THERE WERE UNSENT INFORMATION, SEND IT.                       */
-      /*---------------------------------------------------------------------*/
-      sendSignal(TBRef, GSN_KEYINFO, signal, 3 + len, JBB);
-      return;
-    } else if(len == KeyInfo::DataLength){
-      jam();
-      len = 0;
-      sendSignal(TBRef, GSN_KEYINFO, signal, 3 + KeyInfo::DataLength, JBB);
-    }
-    totalLen -= 4;
-    ptrCheckGuard(databufptr, cdatabufFilesize, databufRecord);
-  } while (1);
-}//Dbtc::packKeyData000Lab()
 
 /**
- * packKeyDataFromSection
- * Method to pack a KeyInfo signal train from KeyInfo in the supplied
+ * sendKeyInfoTrain
+ * Method to send a KeyInfo signal train from KeyInfo in the supplied
  * Section
  * KeyInfo will be taken from the section, starting at the supplied
  * offset
  */
-void Dbtc::packKeyDataFromSection(Signal* signal,
-                                  BlockReference TBRef,
-                                  Uint32 offset,
-                                  SegmentedSectionPtr& section)
+void Dbtc::sendKeyInfoTrain(Signal* signal,
+                            BlockReference TBRef,
+                            Uint32 connectPtr,
+                            Uint32 offset,
+                            Uint32 sectionIVal)
 {
   jam();
 
-  Uint32 totalLen= section.sz;
+  signal->theData[0] = connectPtr;
+  signal->theData[1] = apiConnectptr.p->transid[0];
+  signal->theData[2] = apiConnectptr.p->transid[1];
+  Uint32 * dst = signal->theData + KeyInfo::HeaderLength;
+
+  ndbassert( sectionIVal != RNIL );
+  SectionReader keyInfoReader(sectionIVal, getSectionSegmentPool());
+
+  Uint32 totalLen= keyInfoReader.getSize();
 
   ndbassert( offset < totalLen );
-
-  signal->theData[0] = tcConnectptr.i;
-  signal->theData[1] = apiConnectptr.p->transid[0];
-  signal->theData[2] = apiConnectptr.p->transid[1];
-  Uint32 * dst = signal->theData + KeyInfo::HeaderLength;
   
-  SectionReader keyInfoReader(section, getSectionSegmentPool());
   keyInfoReader.step(offset);
   totalLen-= offset;
 
@@ -1953,7 +1873,7 @@
     sendSignal(TBRef, GSN_KEYINFO, signal, 
                KeyInfo::HeaderLength + dataInSignal, JBB);
   } 
-}//Dbtc::packKeyDataFromSection()
+}//Dbtc::sendKeyInfoTrain()
 
 /**
  * tckeyreq020Lab
@@ -2003,103 +1923,6 @@
   }
 }//Dbtc::tckeyreq020Lab()
 
-/* ------------------------------------------------------------------------- */
-/* -------        SAVE ATTRIBUTE INFORMATION IN OPERATION RECORD     ------- */
-/* ------------------------------------------------------------------------- */
-void Dbtc::saveAttrbuf(Signal* signal) 
-{
-  CacheRecord * const regCachePtr = cachePtr.p;
-  UintR TfirstfreeAttrbuf = cfirstfreeAttrbuf;
-  UintR TattrbufFilesize = cattrbufFilesize;
-  UintR TTcfirstAttrbuf = regCachePtr->firstAttrbuf;
-  UintR Tlen = signal->length() - 3;
-  AttrbufRecord *localAttrbufRecord = attrbufRecord;
-
-  AttrbufRecord * const regAttrPtr = &localAttrbufRecord[TfirstfreeAttrbuf];
-  if (TfirstfreeAttrbuf >= TattrbufFilesize) {
-    TCKEY_abort(signal, 21);
-    return;
-  }//if
-  UintR Tnext = regAttrPtr->attrbuf[ZINBUF_NEXT];
-  if (TTcfirstAttrbuf == RNIL) {
-    jam();
-    regCachePtr->firstAttrbuf = TfirstfreeAttrbuf;
-  } else {
-    AttrbufRecordPtr saAttrbufptr;
-
-    saAttrbufptr.i = regCachePtr->lastAttrbuf;
-    jam();
-    if (saAttrbufptr.i >= TattrbufFilesize) {
-      TCKEY_abort(signal, 22);
-      return;
-    }//if
-    saAttrbufptr.p = &localAttrbufRecord[saAttrbufptr.i];
-    saAttrbufptr.p->attrbuf[ZINBUF_NEXT] = TfirstfreeAttrbuf;
-  }//if
-
-  cfirstfreeAttrbuf = Tnext;
-  regAttrPtr->attrbuf[ZINBUF_NEXT] = RNIL;
-  regCachePtr->lastAttrbuf = TfirstfreeAttrbuf;
-  regAttrPtr->attrbuf[ZINBUF_DATA_LEN] = Tlen;
-
-  UintR Tdata1 = signal->theData[3];
-  UintR Tdata2 = signal->theData[4];
-  UintR Tdata3 = signal->theData[5];
-  UintR Tdata4 = signal->theData[6];
-  UintR Tdata5 = signal->theData[7];
-  UintR Tdata6 = signal->theData[8];
-  UintR Tdata7 = signal->theData[9];
-  UintR Tdata8 = signal->theData[10];
-
-  regAttrPtr->attrbuf[0] = Tdata1;
-  regAttrPtr->attrbuf[1] = Tdata2;
-  regAttrPtr->attrbuf[2] = Tdata3;
-  regAttrPtr->attrbuf[3] = Tdata4;
-  regAttrPtr->attrbuf[4] = Tdata5;
-  regAttrPtr->attrbuf[5] = Tdata6;
-  regAttrPtr->attrbuf[6] = Tdata7;
-  regAttrPtr->attrbuf[7] = Tdata8;
-
-  if (Tlen > 8) {
-
-    Tdata1 = signal->theData[11];
-    Tdata2 = signal->theData[12];
-    Tdata3 = signal->theData[13];
-    Tdata4 = signal->theData[14];
-    Tdata5 = signal->theData[15];
-    Tdata6 = signal->theData[16];
-    Tdata7 = signal->theData[17];
-
-    regAttrPtr->attrbuf[8] = Tdata1;
-    regAttrPtr->attrbuf[9] = Tdata2;
-    regAttrPtr->attrbuf[10] = Tdata3;
-    regAttrPtr->attrbuf[11] = Tdata4;
-    regAttrPtr->attrbuf[12] = Tdata5;
-    regAttrPtr->attrbuf[13] = Tdata6;
-    regAttrPtr->attrbuf[14] = Tdata7;
-    jam();
-    if (Tlen > 15) {
-
-      Tdata1 = signal->theData[18];
-      Tdata2 = signal->theData[19];
-      Tdata3 = signal->theData[20];
-      Tdata4 = signal->theData[21];
-      Tdata5 = signal->theData[22];
-      Tdata6 = signal->theData[23];
-      Tdata7 = signal->theData[24];
-
-      jam();
-      regAttrPtr->attrbuf[15] = Tdata1;
-      regAttrPtr->attrbuf[16] = Tdata2;
-      regAttrPtr->attrbuf[17] = Tdata3;
-      regAttrPtr->attrbuf[18] = Tdata4;
-      regAttrPtr->attrbuf[19] = Tdata5;
-      regAttrPtr->attrbuf[20] = Tdata6;
-      regAttrPtr->attrbuf[21] = Tdata7;
-    }//if
-  }//if
-}//Dbtc::saveAttrbuf()
-
 void Dbtc::execATTRINFO(Signal* signal) 
 {
   UintR Tdata1 = signal->theData[0];
@@ -2508,16 +2331,6 @@
   cachePtr.i = TfirstfreeCacheRec;
   cachePtr.p = regCachePtr;
 
-#ifdef VM_TRACE
-  // This is a good place to check that resources have 
-  // been properly released from CacheRecord
-  ndbrequire(regCachePtr->firstKeybuf == RNIL);
-  ndbrequire(regCachePtr->lastKeybuf == RNIL);
-#endif
-  regCachePtr->firstKeybuf = RNIL;
-  regCachePtr->lastKeybuf = RNIL;
-  regCachePtr->firstAttrbuf = RNIL;
-  regCachePtr->lastAttrbuf = RNIL;
   regCachePtr->currReclenAi = 0;
   regCachePtr->keyInfoSectionI = RNIL;
   regCachePtr->attrInfoSectionI = RNIL;
@@ -3463,14 +3276,11 @@
       (Tkeylen > LqhKeyReq::MaxKeyInfo)) 
   {
     /* Build KeyInfo train from KeyInfo long signal section */
-    SegmentedSectionPtr keyInfoSection;
-
-    getSection(keyInfoSection, regCachePtr->keyInfoSectionI);
-
-    packKeyDataFromSection(signal, 
-                           TBRef, 
-                           LqhKeyReq::MaxKeyInfo,
-                           keyInfoSection);
+    sendKeyInfoTrain(signal, 
+                     TBRef,
+                     tcConnectptr.i,
+                     LqhKeyReq::MaxKeyInfo,
+                     regCachePtr->keyInfoSectionI);
   }//if
 
   /* Release key storage */ 
@@ -3748,14 +3558,12 @@
 
   if (ERROR_INSERTED(8009)) {
     if (regApiPtr->apiConnectstate == CS_STARTED) {
-      attrbufptr.i = RNIL;
       CLEAR_ERROR_INSERT_VALUE;
       return;
     }//if
   }//if
   if (ERROR_INSERTED(8010)) {
     if (regApiPtr->apiConnectstate == CS_START_COMMITTING) {
-      attrbufptr.i = RNIL;
       CLEAR_ERROR_INSERT_VALUE;
       return;
     }//if
@@ -3768,14 +3576,11 @@
     /* Short LqhKeyReq */
     if (regCachePtr->attrlength > LqhKeyReq::MaxAttrInfo)
     {
-      SegmentedSectionPtr attrInfoSection;
-
-      getSection(attrInfoSection, regCachePtr->attrInfoSectionI);
-
       if (unlikely( !sendAttrInfoTrain(signal,
                                        TBRef,
+                                       tcConnectptr.i,
                                        LqhKeyReq::MaxAttrInfo,
-                                       attrInfoSection)))
+                                       regCachePtr->attrInfoSectionI)))
       {
         jam();
         TCKEY_abort(signal, 17);
@@ -3810,27 +3615,7 @@
 /* ========================================================================= */
 void Dbtc::releaseAttrinfo() 
 {
-  UintR Tmp;
-  AttrbufRecordPtr Tattrbufptr;
   CacheRecord * const regCachePtr = cachePtr.p;
-  UintR TattrbufFilesize = cattrbufFilesize;
-  UintR TfirstfreeAttrbuf = cfirstfreeAttrbuf;
-  Tattrbufptr.i = regCachePtr->firstAttrbuf;
-  AttrbufRecord *localAttrbufRecord = attrbufRecord;
-
-  while (Tattrbufptr.i < TattrbufFilesize) {
-    Tattrbufptr.p = &localAttrbufRecord[Tattrbufptr.i];
-    Tmp = Tattrbufptr.p->attrbuf[ZINBUF_NEXT];
-    Tattrbufptr.p->attrbuf[ZINBUF_NEXT] = TfirstfreeAttrbuf;
-    TfirstfreeAttrbuf = Tattrbufptr.i;
-    Tattrbufptr.i = Tmp;
-    jam();
-  }//while
-  if (Tattrbufptr.i != RNIL) {
-    systemErrorLab(0, __LINE__);
-    return;
-  }
-
   Uint32 attrInfoSectionI= cachePtr.p->attrInfoSectionI;
 
   /* Release AttrInfo section if there is one */
@@ -3844,7 +3629,6 @@
   ApiConnectRecord * const regApiPtr = apiConnectptr.p;
   UintR TfirstfreeCacheRec = cfirstfreeCacheRec;
   UintR TCacheIndex = cachePtr.i;
-  cfirstfreeAttrbuf = TfirstfreeAttrbuf;
   regCachePtr->nextCacheRec = TfirstfreeCacheRec;
   cfirstfreeCacheRec = TCacheIndex;
   regApiPtr->cachePtr = RNIL;
@@ -4035,9 +3819,6 @@
 
   DEBUG("SignalDroppedRep received for GSN " << originalGSN);
 
-  // TODO : Add handling for long signal variants as they
-  //        are added here (SCANTABREQ etc.)
-
   switch(originalGSN) {
   case GSN_TCKEYREQ:
     jam(); 
@@ -4093,6 +3874,40 @@
 
     break;
   }
+  case GSN_SCAN_TABREQ:
+  {
+    jam();
+    /* Get information necessary to send SCAN_TABREF back to client */
+    const ScanTabReq * const truncatedScanTabReq = 
+      (ScanTabReq *) &rep->originalData[0];
+
+    Uint32 apiConnectPtr= truncatedScanTabReq->apiConnectPtr;
+    Uint32 transId1= truncatedScanTabReq->transId1;
+    Uint32 transId2= truncatedScanTabReq->transId2;
+    
+    if (apiConnectPtr >= capiConnectFilesize)
+    {
+      jam();
+      warningHandlerLab(signal, __LINE__);
+      return;
+    }//if
+    
+    apiConnectptr.i = apiConnectPtr;
+    ptrAss(apiConnectptr, apiConnectRecord);
+    ApiConnectRecord * transP = apiConnectptr.p;
+    
+    /* Now send the SCAN_TABREF */
+    ScanTabRef* ref= (ScanTabRef*)&signal->theData[0];
+    ref->apiConnectPtr = transP->ndbapiConnect;
+    ref->transId1= transId1;
+    ref->transId2= transId2;
+    ref->errorCode= ZGET_ATTRBUF_ERROR;
+    ref->closeNeeded= 0;
+
+    sendSignal(transP->ndbapiBlockref, GSN_SCAN_TABREF,
+               signal, ScanTabRef::SignalLength, JBB);
+    break;
+  }
   default:
     jam();
     /* Don't expect dropped signals for other GSNs,
@@ -5719,7 +5534,6 @@
 	return;
       }//if
 
-      const ConnectionState state = regApiPtr->apiConnectstate;
       const Uint32 triggeringOp = regTcPtr->triggeringOperation;
       if (triggeringOp != RNIL) {
         jam();
@@ -9510,12 +9324,6 @@
   abortErrorLab(signal);
 }//Dbtc::aiErrorLab()
 
-void Dbtc::seizeAttrbuferrorLab(Signal* signal) 
-{
-  terrorCode = ZGET_ATTRBUF_ERROR;
-  abortErrorLab(signal);
-}//Dbtc::seizeAttrbuferrorLab()
-
 void Dbtc::seizeDatabuferrorLab(Signal* signal) 
 {
   terrorCode = ZGET_DATAREC_ERROR;
@@ -9524,7 +9332,7 @@
 
 void Dbtc::appendToSectionErrorLab(Signal* signal)
 {
-  terrorCode = ZGET_DATAREC_ERROR; // TODO : New error?
+  terrorCode = ZGET_DATAREC_ERROR;
   releaseAtErrorLab(signal);
 }//Dbtc::appendToSectionErrorLab
 
@@ -9650,10 +9458,16 @@
   * ######################################################################## */
 void Dbtc::execSCAN_TABREQ(Signal* signal) 
 {
+  jamEntry();
+
+  /* Reassemble if the request was fragmented */
+  if (!assembleFragments(signal)){
+    jam();
+    return;
+  }
+
   const ScanTabReq * const scanTabReq = (ScanTabReq *)&signal->theData[0];
   const Uint32 ri = scanTabReq->requestInfo;
-  const Uint32 aiLength = (scanTabReq->attrLenKeyLen & 0xFFFF);
-  const Uint32 keyLen = scanTabReq->attrLenKeyLen >> 16;
   const Uint32 schemaVersion = scanTabReq->tableSchemaVersion;
   const Uint32 transid1 = scanTabReq->transId1;
   const Uint32 transid2 = scanTabReq->transId2;
@@ -9667,14 +9481,42 @@
   Uint32 errCode;
   ScanRecordPtr scanptr;
 
-  jamEntry();
+  /* Short SCANTABREQ has 1 section, Long has 2 or 3.
+   * Section 0 : NDBAPI receiver ids (Mandatory)
+   * Section 1 : ATTRINFO section (Mandatory for long SCAN_TABREQ
+   * Section 2 : KEYINFO section (Optional for long SCAN_TABREQ
+   */
+  Uint32 numSections= signal->getNoOfSections();
+  ndbassert( numSections >= 1 );
+  bool isLongReq= numSections >= 2;
 
-  ndbassert( signal->getNoOfSections() == 1 );
   SectionHandle handle(this, signal);
   SegmentedSectionPtr api_op_ptr;
   handle.getSection(api_op_ptr, 0);
   copy(&cdata[0], api_op_ptr);
-  releaseSections(handle);
+
+  Uint32 aiLength= 0;
+  Uint32 keyLen= 0;
+
+  if (likely(isLongReq))
+  {
+    SegmentedSectionPtr attrInfoPtr, keyInfoPtr;
+    /* Long SCANTABREQ, determine Ai and Key length from sections */
+    handle.getSection(attrInfoPtr, ScanTabReq::AttrInfoSectionNum);
+    aiLength= attrInfoPtr.sz;
+    if (numSections == 3)
+    {
+      handle.getSection(keyInfoPtr, ScanTabReq::KeyInfoSectionNum);
+      keyLen= keyInfoPtr.sz;
+    }
+  }
+  else
+  {
+    /* Short SCANTABREQ, get Ai and Key length from signal */
+    aiLength = (scanTabReq->attrLenKeyLen & 0xFFFF);
+    keyLen = scanTabReq->attrLenKeyLen >> 16;
+  }
+
 
   apiConnectptr.i = scanTabReq->apiConnectPtr;
   tabptr.i = scanTabReq->tableId;
@@ -9682,6 +9524,7 @@
   if (apiConnectptr.i >= capiConnectFilesize)
   {
     jam();
+    releaseSections(handle);
     warningHandlerLab(signal, __LINE__);
     return;
   }//if
@@ -9755,6 +9598,18 @@
   apiConnectptr.p->lastTcConnect = tcConnectptr.i;
 
   seizeCacheRecord(signal);
+
+  if (likely(isLongReq))
+  {
+    /* We keep the AttrInfo and KeyInfo sections */
+    cachePtr.p->attrInfoSectionI= handle.m_ptr[ScanTabReq::AttrInfoSectionNum].i;
+    if (keyLen)
+      cachePtr.p->keyInfoSectionI= handle.m_ptr[ScanTabReq::KeyInfoSectionNum].i;
+  }
+
+  releaseSection(handle.m_ptr[ScanTabReq::ReceiverIdSectionNum].i);
+  handle.clear();
+
   cachePtr.p->keylen = keyLen;
   cachePtr.p->save1 = 0;
   cachePtr.p->distributionKey = scanTabReq->distributionKey;
@@ -9764,7 +9619,8 @@
   ndbrequire(transP->apiScanRec == RNIL);
   ndbrequire(scanptr.p->scanApiRec == RNIL);
 
-  initScanrec(scanptr, scanTabReq, scanParallel, noOprecPerFrag);
+  initScanrec(scanptr, scanTabReq, scanParallel, 
+              noOprecPerFrag, aiLength, keyLen);
 
   transP->apiScanRec = scanptr.i;
   transP->returncode = 0;
@@ -9789,7 +9645,7 @@
    * IF ANY TO RECEIVE.
    **********************************************************/
   scanptr.p->scanState = ScanRecord::WAIT_AI;
-  
+
   if (ERROR_INSERTED(8038))
   {
     /**
@@ -9802,6 +9658,14 @@
     sendSignal(CMVMI_REF, GSN_DISCONNECT_REP, signal, 2, JBA);
     CLEAR_ERROR_INSERT_VALUE;
   }
+
+  if (isLongReq)
+  {
+    /* All AttrInfo (and KeyInfo) has been received, continue
+     * processing
+     */
+    diFcountReqLab(signal, scanptr);
+  }
   
   return;
 
@@ -9843,6 +9707,8 @@
  
 SCAN_TAB_error_no_state_change:
   
+  releaseSections(handle);
+
   ScanTabRef * ref = (ScanTabRef*)&signal->theData[0];
   ref->apiConnectPtr = transP->ndbapiConnect;
   ref->transId1 = transid1;
@@ -9857,13 +9723,15 @@
 void Dbtc::initScanrec(ScanRecordPtr scanptr,
 		       const ScanTabReq * scanTabReq,
 		       UintR scanParallel,
-		       UintR noOprecPerFrag) 
+		       UintR noOprecPerFrag,
+                       Uint32 aiLength,
+                       Uint32 keyLength) 
 {
   const UintR ri = scanTabReq->requestInfo;
   scanptr.p->scanTcrec = tcConnectptr.i;
   scanptr.p->scanApiRec = apiConnectptr.i;
-  scanptr.p->scanAiLength = scanTabReq->attrLenKeyLen & 0xFFFF;
-  scanptr.p->scanKeyLen = scanTabReq->attrLenKeyLen >> 16;
+  scanptr.p->scanAiLength = aiLength;
+  scanptr.p->scanKeyLen = keyLength;
   scanptr.p->scanTableref = tabptr.i;
   scanptr.p->scanSchemaVersion = scanTabReq->tableSchemaVersion;
   scanptr.p->scanParallel = scanParallel;
@@ -9879,7 +9747,7 @@
   ScanFragReq::setRangeScanFlag(tmp, ScanTabReq::getRangeScanFlag(ri));
   ScanFragReq::setDescendingFlag(tmp, ScanTabReq::getDescendingFlag(ri));
   ScanFragReq::setTupScanFlag(tmp, ScanTabReq::getTupScanFlag(ri));
-  ScanFragReq::setAttrLen(tmp, scanTabReq->attrLenKeyLen & 0xFFFF);
+  ScanFragReq::setAttrLen(tmp, aiLength);
   ScanFragReq::setNoDiskFlag(tmp, ScanTabReq::getNoDiskFlag(ri));
   
   scanptr.p->scanRequestInfo = tmp;
@@ -9918,6 +9786,53 @@
 	     signal, ScanTabRef::SignalLength, JBB);
 }//Dbtc::scanTabRefLab()
 
+/**
+ * scanKeyinfoLab
+ * Handle reception of KeyInfo for a Scan
+ */
+void Dbtc::scanKeyinfoLab(Signal* signal)
+{
+  /* Receive KEYINFO for a SCAN operation 
+   * Note that old NDBAPI nodes sometimes send header-only KEYINFO signals
+   */
+  CacheRecord * const regCachePtr = cachePtr.p;
+  UintR TkeyLen = regCachePtr->keylen;
+  UintR Tlen = regCachePtr->save1;
+
+  Uint32 wordsInSignal= MIN(KeyInfo::DataLength,
+                            (TkeyLen - Tlen));
+
+  ndbassert( signal->getLength() == 
+             (KeyInfo::HeaderLength + wordsInSignal) );
+
+  if (unlikely (! appendToSection(regCachePtr->keyInfoSectionI,
+                                  &signal->theData[KeyInfo::HeaderLength],
+                                  wordsInSignal)))
+  {
+    jam();
+    seizeDatabuferrorLab(signal);
+    return;
+  }
+
+  Tlen+= wordsInSignal;
+  regCachePtr->save1 = Tlen;
+  
+  if (Tlen < TkeyLen)
+  {
+    jam();
+    /* More KeyInfo still to come - continue waiting */
+    setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__);
+    return;
+  }
+
+  /* All KeyInfo has been received, we will now start receiving
+   * ATTRINFO
+   */
+  jam();
+  ndbassert(Tlen == TkeyLen);
+  return;
+} // scanKeyinfoLab
+
 /*---------------------------------------------------------------------------*/
 /*                                                                           */
 /*       RECEPTION OF ATTRINFO FOR SCAN TABLE REQUEST.                       */
@@ -9935,44 +9850,32 @@
   ndbrequire(scanptr.p->scanState == ScanRecord::WAIT_AI);
 
   regCachePtr->currReclenAi = regCachePtr->currReclenAi + Tlen;
-  if (regCachePtr->currReclenAi < scanptr.p->scanAiLength) {
-    if (cfirstfreeAttrbuf == RNIL) {
-      goto scanAttrinfo_attrbuf_error;
-    }//if
-    saveAttrbuf(signal);
-  } else {
-    if (regCachePtr->currReclenAi > scanptr.p->scanAiLength) {
-      goto scanAttrinfo_len_error;
-    } else {
-      /* CURR_RECLEN_AI = SCAN_AI_LENGTH */
-      if (cfirstfreeAttrbuf == RNIL) {
-        goto scanAttrinfo_attrbuf2_error;
-      }//if
-      saveAttrbuf(signal);
-      /**************************************************
-       * WE HAVE NOW RECEIVED ALL INFORMATION CONCERNING 
-       * THIS SCAN. WE ARE READY TO START THE ACTUAL 
-       * EXECUTION OF THE SCAN QUERY
-       **************************************************/
-      diFcountReqLab(signal, scanptr);
-      return;
-    }//if
-  }//if
-  return;
-
-scanAttrinfo_attrbuf_error:
-  jam();
-  abortScanLab(signal, scanptr, ZGET_ATTRBUF_ERROR, true);
-  return;
-
-scanAttrinfo_attrbuf2_error:
-  jam();
-  abortScanLab(signal, scanptr, ZGET_ATTRBUF_ERROR, true);
-  return;
-
-scanAttrinfo_len_error:
-  jam();
-  abortScanLab(signal, scanptr, ZLENGTH_ERROR, true);
+
+  if (unlikely(! appendToSection(regCachePtr->attrInfoSectionI,
+                                 &signal->theData[AttrInfo::HeaderLength],
+                                 Tlen)))
+  {
+    jam();
+    abortScanLab(signal, scanptr, ZGET_ATTRBUF_ERROR, true);
+    return;
+  }
+  
+  if (regCachePtr->currReclenAi == scanptr.p->scanAiLength)
+  {
+    /* We have now received all the signals defining this
+     * scan.  We are ready to start executing the scan
+     */
+    diFcountReqLab(signal, scanptr);
+    return;
+  }
+  else if (unlikely (regCachePtr->currReclenAi > scanptr.p->scanAiLength))
+  {
+    jam();
+    abortScanLab(signal, scanptr, ZLENGTH_ERROR, true);
+    return;
+  }
+  
+  /* Still some ATTRINFO to arrive...*/
   return;
 }//Dbtc::scanAttrinfoLab()
 
@@ -10327,25 +10230,34 @@
     /*empty*/;
     break;
   }//switch
+  
+  /* Send SCANFRAGREQ to LQH block
+   * SCANFRAGREQ with optional KEYINFO and mandatory ATTRINFO are
+   * now sent to LQH
+   * This starts the scan on the given fragment.
+   */
   Uint32 instanceKey = conf->instanceKey;
   Uint32 ref = numberToRef(DBLQH, instanceKey, tnodeid);
   scanFragptr.p->lqhBlockref = ref;
   scanFragptr.p->m_connectCount = getNodeInfo(tnodeid).m_connectCount;
+
   sendScanFragReq(signal, scanptr.p, scanFragptr.p);
-  if(ERROR_INSERTED(8035))
-    globalTransporterRegistry.performSend();
-  attrbufptr.i = cachePtr.p->firstAttrbuf;
-  while (attrbufptr.i != RNIL) {
-    jam();
-    ptrCheckGuard(attrbufptr, cattrbufFilesize, attrbufRecord);
-    sendAttrinfo(signal,
-                 scanFragptr.i,
-                 attrbufptr.p,
-                 ref);
-    attrbufptr.i = attrbufptr.p->attrbuf[ZINBUF_NEXT];
-    if(ERROR_INSERTED(8035))
-      globalTransporterRegistry.performSend();
-  }//while
+
+  if(ERROR_INSERTED(8035))
+    globalTransporterRegistry.performSend();
+   
+  ndbrequire(sendAttrInfoTrain(signal,
+                               ref,
+                               scanFragptr.i,
+                               0, // Offset 0
+                               cachePtr.p->attrInfoSectionI));
+
+  // TODO : Consider determining whether KEYINFO and ATTRINFO can be
+  //        freed here
+
+  if(ERROR_INSERTED(8035))
+    globalTransporterRegistry.performSend();
+
   scanFragptr.p->scanFragState = ScanFragRec::LQH_ACTIVE;
   scanFragptr.p->startFragTimer(ctcTimer);
   updateBuddyTimer(apiConnectptr);
@@ -10934,6 +10846,8 @@
 			   ScanRecord* scanP, 
 			   ScanFragRec* scanFragP)
 {
+  cachePtr.i = apiConnectptr.p->cachePtr;
+  ptrCheckGuard(cachePtr, ccacheFilesize, cacheRecord);
   ScanFragReq * const req = (ScanFragReq *)&signal->theData[0];
   Uint32 requestInfo = scanP->scanRequestInfo;
   ScanFragReq::setScanPrio(requestInfo, 1);
@@ -10956,7 +10870,12 @@
   if(scanP->scanKeyLen > 0)
   {
     tcConnectptr.i = scanFragptr.i;
-    packKeyData000Lab(signal, scanFragP->lqhBlockref, scanP->scanKeyLen);
+    /* Build KeyInfo train from KeyInfo long signal section */
+    sendKeyInfoTrain(signal,
+                     scanFragP->lqhBlockref,
+                     scanFragptr.i,
+                     0, // Offset 0
+                     cachePtr.p->keyInfoSectionI);
   }
   updateBuddyTimer(apiConnectptr);
   scanFragP->startFragTimer(ctcTimer);
@@ -11075,10 +10994,6 @@
   for (cachePtr.i = 0; cachePtr.i < guard4; cachePtr.i++) {
     refresh_watch_dog();
     ptrAss(cachePtr, cacheRecord);
-    cachePtr.p->firstAttrbuf = RNIL;
-    cachePtr.p->lastAttrbuf = RNIL;
-    cachePtr.p->firstKeybuf = RNIL;
-    cachePtr.p->lastKeybuf = RNIL;
     cachePtr.p->nextCacheRec = cachePtr.i + 1;
   }//for
   cachePtr.i = tiacTmp;
@@ -11174,35 +11089,6 @@
   cfirstfreeApiConnectFail = 2 * tiacTmp;
 }//Dbtc::initApiConnect()
 
-void Dbtc::initattrbuf(Signal* signal) 
-{
-  ndbrequire(cattrbufFilesize > 0);
-  for (attrbufptr.i = 0; attrbufptr.i < cattrbufFilesize; attrbufptr.i++) {
-    refresh_watch_dog();
-    jam();
-    ptrAss(attrbufptr, attrbufRecord);
-    attrbufptr.p->attrbuf[ZINBUF_NEXT] = attrbufptr.i + 1;  /* NEXT ATTRBUF */
-  }//for
-  attrbufptr.i = cattrbufFilesize - 1;
-  ptrAss(attrbufptr, attrbufRecord);
-  attrbufptr.p->attrbuf[ZINBUF_NEXT] = RNIL;    /* NEXT ATTRBUF */
-  cfirstfreeAttrbuf = 0;
-}//Dbtc::initattrbuf()
-
-void Dbtc::initdatabuf(Signal* signal) 
-{
-  ndbrequire(cdatabufFilesize > 0);
-  for (databufptr.i = 0; databufptr.i < cdatabufFilesize; databufptr.i++) {
-    refresh_watch_dog();
-    ptrAss(databufptr, databufRecord);
-    databufptr.p->nextDatabuf = databufptr.i + 1;
-  }//for
-  databufptr.i = cdatabufFilesize - 1;
-  ptrCheckGuard(databufptr, cdatabufFilesize, databufRecord);
-  databufptr.p->nextDatabuf = RNIL;
-  cfirstfreeDatabuf = 0;
-}//Dbtc::initdatabuf()
-
 void Dbtc::initgcp(Signal* signal) 
 {
   Ptr<GcpRecord> gcpPtr;
@@ -11248,11 +11134,11 @@
     break;
   case 1:
     jam();
-    initattrbuf(signal);
+    // UNUSED Free to initialise something
     break;
   case 2:
     jam();
-    initdatabuf(signal);
+    // UNUSED Free to initialise something
     break;
   case 3:
     jam();
@@ -11423,24 +11309,6 @@
 }//Dbtc::linkGciInGcilist()
 
 /* ------------------------------------------------------------------------- */
-/* -------        LINK SECONDARY KEY BUFFER IN OPERATION RECORD      ------- */
-/* ------------------------------------------------------------------------- */
-void Dbtc::linkKeybuf(Signal* signal) 
-{
-  seizeDatabuf(signal);
-  tmpDatabufptr.i = cachePtr.p->lastKeybuf;
-  cachePtr.p->lastKeybuf = databufptr.i;
-  if (tmpDatabufptr.i == RNIL) {
-    jam();
-    cachePtr.p->firstKeybuf = databufptr.i;
-  } else {
-    jam();
-    ptrCheckGuard(tmpDatabufptr, cdatabufFilesize, databufRecord);
-    tmpDatabufptr.p->nextDatabuf = databufptr.i;
-  }//if
-}//Dbtc::linkKeybuf()
-
-/* ------------------------------------------------------------------------- */
 /* ------- LINK A TC CONNECT RECORD INTO THE API LIST OF TC CONNECTIONS  --- */
 /* ------------------------------------------------------------------------- */
 void Dbtc::linkTcInConnectionlist(Signal* signal) 
@@ -11583,19 +11451,6 @@
 
 void Dbtc::releaseKeys() 
 {
-  UintR Tmp;
-  databufptr.i = cachePtr.p->firstKeybuf;
-  while (databufptr.i != RNIL) {
-    jam();
-    ptrCheckGuard(databufptr, cdatabufFilesize, databufRecord);
-    Tmp = databufptr.p->nextDatabuf;
-    databufptr.p->nextDatabuf = cfirstfreeDatabuf;
-    cfirstfreeDatabuf = databufptr.i;
-    databufptr.i = Tmp;
-  }//while
-  cachePtr.p->firstKeybuf = RNIL;
-  cachePtr.p->lastKeybuf = RNIL;
-  
   Uint32 keyInfoSectionI= cachePtr.p->keyInfoSectionI;
 
   /* Release KeyInfo section if there is one */
@@ -11637,14 +11492,6 @@
   cfirstfreeApiConnectFail = apiConnectptr.p->nextApiConnect;
 }//Dbtc::seizeApiConnectFail()
 
-void Dbtc::seizeDatabuf(Signal* signal) 
-{
-  databufptr.i = cfirstfreeDatabuf;
-  ptrCheckGuard(databufptr, cdatabufFilesize, databufRecord);
-  cfirstfreeDatabuf = databufptr.p->nextDatabuf;
-  databufptr.p->nextDatabuf = RNIL;
-}//Dbtc::seizeDatabuf()
-
 void Dbtc::seizeTcConnect(Signal* signal) 
 {
   tcConnectptr.i = cfirstfreeTcConnect;
@@ -11661,82 +11508,6 @@
   cfirstfreeTcConnectFail = tcConnectptr.p->nextTcConnect;
 }//Dbtc::seizeTcConnectFail()
 
-void Dbtc::sendAttrinfo(Signal* signal,
-                        UintR TattrinfoPtr,
-                        AttrbufRecord * const regAttrPtr,
-                        UintR TBref) 
-{
-  UintR TdataPos;
-  UintR sig0, sig1, sig2, sig3, sig4, sig5, sig6, sig7;
-  ApiConnectRecord * const regApiPtr = apiConnectptr.p;
-  TdataPos = regAttrPtr->attrbuf[ZINBUF_DATA_LEN];
-  sig0 = TattrinfoPtr;
-  sig1 = regApiPtr->transid[0];
-  sig2 = regApiPtr->transid[1];
-
-  signal->theData[0] = sig0;
-  signal->theData[1] = sig1;
-  signal->theData[2] = sig2;
-
-  sig0 = regAttrPtr->attrbuf[0];
-  sig1 = regAttrPtr->attrbuf[1];
-  sig2 = regAttrPtr->attrbuf[2];
-  sig3 = regAttrPtr->attrbuf[3];
-  sig4 = regAttrPtr->attrbuf[4];
-  sig5 = regAttrPtr->attrbuf[5];
-  sig6 = regAttrPtr->attrbuf[6];
-  sig7 = regAttrPtr->attrbuf[7];
-
-  signal->theData[3] = sig0;
-  signal->theData[4] = sig1;
-  signal->theData[5] = sig2;
-  signal->theData[6] = sig3;
-  signal->theData[7] = sig4;
-  signal->theData[8] = sig5;
-  signal->theData[9] = sig6;
-  signal->theData[10] = sig7;
-
-  if (TdataPos > 8) {
-    sig0 = regAttrPtr->attrbuf[8];
-    sig1 = regAttrPtr->attrbuf[9];
-    sig2 = regAttrPtr->attrbuf[10];
-    sig3 = regAttrPtr->attrbuf[11];
-    sig4 = regAttrPtr->attrbuf[12];
-    sig5 = regAttrPtr->attrbuf[13];
-    sig6 = regAttrPtr->attrbuf[14];
-
-    jam();
-    signal->theData[11] = sig0;
-    signal->theData[12] = sig1;
-    signal->theData[13] = sig2;
-    signal->theData[14] = sig3;
-    signal->theData[15] = sig4;
-    signal->theData[16] = sig5;
-    signal->theData[17] = sig6;
-
-    if (TdataPos > 15) {
-
-      sig0 = regAttrPtr->attrbuf[15];
-      sig1 = regAttrPtr->attrbuf[16];
-      sig2 = regAttrPtr->attrbuf[17];
-      sig3 = regAttrPtr->attrbuf[18];
-      sig4 = regAttrPtr->attrbuf[19];
-      sig5 = regAttrPtr->attrbuf[20];
-      sig6 = regAttrPtr->attrbuf[21];
-
-      jam();
-      signal->theData[18] = sig0;
-      signal->theData[19] = sig1;
-      signal->theData[20] = sig2;
-      signal->theData[21] = sig3;
-      signal->theData[22] = sig4;
-      signal->theData[23] = sig5;
-      signal->theData[24] = sig6;
-    }//if
-  }//if
-  sendSignal(TBref, GSN_ATTRINFO, signal, TdataPos + 3, JBB);
-}//Dbtc::sendAttrinfo()
-
 /**
  * sendAttrInfoTrain
  * This method sends an ATTRINFO signal train using AttrInfo
@@ -11744,20 +11515,22 @@
  */
 bool Dbtc::sendAttrInfoTrain(Signal* signal,
                              UintR TBRef,
+                             Uint32 connectPtr,
                              Uint32 offset,
-                             SegmentedSectionPtr& section)
+                             Uint32 attrInfoIVal)
 {
   ApiConnectRecord * const regApiPtr = apiConnectptr.p;
+
+  ndbassert( attrInfoIVal != RNIL );
+  SectionReader attrInfoReader(attrInfoIVal, getSectionSegmentPool());  
+  Uint32 attrInfoLength= attrInfoReader.getSize();
   
-  Uint32 attrInfoLength= section.sz;
-  SectionReader attrInfoReader(section, getSectionSegmentPool());
-    
   ndbassert( offset < attrInfoLength );
   if (unlikely(! attrInfoReader.step( offset )))
     return false;
   attrInfoLength-= offset;
 
-  signal->theData[0] = tcConnectptr.i;
+  signal->theData[0] = connectPtr;
   signal->theData[1] = regApiPtr->transid[0];
   signal->theData[2] = regApiPtr->transid[1];
 
@@ -11775,7 +11548,7 @@
     attrInfoLength-= dataInSignal;
   }
   return true;
-} //Dbtc::sendAttrInfosFromSection()
+} //Dbtc::sendAttrInfoTrain()
 
 void Dbtc::sendContinueTimeOutControl(Signal* signal, Uint32 TapiConPtr) 
 {
@@ -12617,7 +12390,6 @@
   const Uint32 senderData = req->senderData;
   TcIndexData* indexData;
   const Uint32 requestType = req->requestType;
-  const Uint32 tableId = req->tableId;
   const Uint32 indexId = req->indexId;
 
   if ((indexData = c_theIndexes.getPtr(indexId)) == NULL) {
@@ -12793,7 +12565,6 @@
   const Uint32 senderRef = req->senderRef;
   const Uint32 senderData = req->senderData;
   TcIndexData* indexData;
-  BlockReference sender = signal->senderBlockRef();
   
   if (ERROR_INSERTED(8036) ||
       (indexData = c_theIndexes.getPtr(req->indexId)) == NULL) {

=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp	2008-08-07 12:32:06 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp	2008-08-26 14:05:01 +0000
@@ -965,7 +965,7 @@
 }
 
 
-#define MAX_READ (sizeof(signal->theData) > MAX_MESSAGE_SIZE ? MAX_MESSAGE_SIZE : sizeof(signal->theData))
+#define MAX_READ (MIN(sizeof(signal->theData), MAX_RECV_MESSAGE_BYTESIZE))
 
 /* ---------------------------------------------------------------- */
 /* ----------------------------- READ  ---------------------------- */

=== modified file 'storage/ndb/src/kernel/vm/SectionReader.cpp'
--- a/storage/ndb/src/kernel/vm/SectionReader.cpp	2008-08-07 11:52:50 +0000
+++ b/storage/ndb/src/kernel/vm/SectionReader.cpp	2008-08-26 14:05:01 +0000
@@ -131,34 +131,23 @@
   if(m_pos + len > m_len)
     return false;
 
-  Uint32 ind = (m_pos % SectionSegment::DataLength);
-  Uint32 left = SectionSegment::DataLength - ind;
-  SectionSegment * p = m_currentSegment;
-
-  while(len > left){
-    memcpy(dst, &p->theData[ind], 4 * left);
-    dst += left;
-    len -= left;
-    m_pos += left;
-    ind = 0;
-    left = SectionSegment::DataLength;
-    p = m_pool.getPtr(p->m_nextSegment);
+  /* Use getWordsPtr to correctly traverse segments */
+
+  while (len > 0)
+  {
+    const Uint32* readPtr;
+    Uint32 readLen;
+
+    if (!getWordsPtr(len,
+                     readPtr,
+                     readLen))
+      return false;
+    
+    memcpy(dst, readPtr, readLen << 2);
+    len-= readLen;
+    dst+= readLen;
   }
 
-  memcpy(dst, &p->theData[ind], 4 * len);
-
-  m_pos += len;
-
-  /* If we read everything in the current
-   * segment, and there's another segment,
-   * move onto it for next time
-   */
-  if (unlikely((len == left) &&
-               (p->m_nextSegment != RNIL)))
-    p= m_pool.getPtr(p->m_nextSegment);
-  else
-    m_currentSegment = p;
-  
   return true;
 }
 

=== modified file 'storage/ndb/src/kernel/vm/SimulatedBlock.cpp'
--- a/storage/ndb/src/kernel/vm/SimulatedBlock.cpp	2008-08-22 11:02:38 +0000
+++ b/storage/ndb/src/kernel/vm/SimulatedBlock.cpp	2008-08-26 14:05:01 +0000
@@ -309,6 +309,20 @@
   Ptr<SectionSegment> oldTailPtr;
   g_sectionSegmentPool.getPtr(oldTailPtr, headPtr.p->m_lastSegment);
   
+  /* Can only efficiently link segments if linking to the end of a 
+   * multiple-of-segment-size sized chunk
+   */
+  if ((headPtr.p->m_sz % NDB_SECTION_SEGMENT_SZ) != 0)
+  {
+#if defined VM_TRACE || defined ERROR_INSERT
+    ErrorReporter::handleError(NDBD_EXIT_BLOCK_BNR_ZERO,
+                               "Bad head segment size",
+                               "");
+#else
+    infoEvent("linkSegments : Bad head segment size");
+#endif
+  }
+
   headPtr.p->m_lastSegment = tailPtr.p->m_lastSegment;
   headPtr.p->m_sz += tailPtr.p->m_sz;
   

=== modified file 'storage/ndb/src/ndbapi/Makefile.am'
--- a/storage/ndb/src/ndbapi/Makefile.am	2008-04-25 06:32:23 +0000
+++ b/storage/ndb/src/ndbapi/Makefile.am	2008-08-26 14:05:01 +0000
@@ -89,3 +89,11 @@
 	@$(top_srcdir)/storage/ndb/config/win-includes $@ $(INCLUDES)
 	@$(top_srcdir)/storage/ndb/config/win-sources $@ $(libndbapi_la_SOURCES)
 	@$(top_srcdir)/storage/ndb/config/win-libraries $@ LIB $(LDADD)
+
+EXTRA_PROGRAMS = testSectionIterators
+
+testSectionIterators_CXXFLAGS = -DUNIT_TEST
+testSectionIterators_SOURCES = TransporterFacade.cpp
+testSectionIterators_LDFLAGS = @ndb_bin_am_ldflags@	 \
+  $(top_builddir)/storage/ndb/src/libndbclient.la
+

=== 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-08-26 14:05:01 +0000
@@ -214,6 +214,26 @@
 void
 NdbOperation::release()
 {
+  NdbBlob* tBlob;
+  NdbBlob* tSaveBlob;
+
+  /* In case we didn't execute... */
+  postExecuteRelease();
+
+  tBlob = theBlobList;
+  while (tBlob != NULL)
+  {
+    tSaveBlob = tBlob;
+    tBlob = tBlob->theNext;
+    theNdb->releaseNdbBlob(tSaveBlob);
+  }
+  theBlobList = NULL;
+  theReceiver.release();
+}
+
+void
+NdbOperation::postExecuteRelease()
+{
   NdbApiSignal* tSignal;
   NdbApiSignal* tSaveSignal;
   NdbBranch*	tBranch;
@@ -224,17 +244,15 @@
   NdbCall*	tSaveCall;
   NdbSubroutine* tSubroutine;
   NdbSubroutine* tSaveSubroutine;
-  NdbBlob* tBlob;
-  NdbBlob* tSaveBlob;
 
-  tSignal = theTCREQ;
+  tSignal = theRequest; /* TCKEYREQ/TCINDXREQ/SCANTABREQ */
   while (tSignal != NULL)
   {
     tSaveSignal = tSignal;
     tSignal = tSignal->next();
     theNdb->releaseSignal(tSaveSignal);
   }				
-  theTCREQ = NULL;
+  theRequest = NULL;
   theLastKEYINFO = NULL;
 
   tSignal = theFirstATTRINFO;
@@ -278,15 +296,6 @@
       theNdb->releaseNdbSubroutine(tSaveSubroutine);
     }
   }
-  tBlob = theBlobList;
-  while (tBlob != NULL)
-  {
-    tSaveBlob = tBlob;
-    tBlob = tBlob->theNext;
-    theNdb->releaseNdbBlob(tSaveBlob);
-  }
-  theBlobList = NULL;
-  theReceiver.release();
 }
 
 NdbRecAttr*

=== modified file 'storage/ndb/src/ndbapi/NdbOperationExec.cpp'
--- a/storage/ndb/src/ndbapi/NdbOperationExec.cpp	2008-08-05 10:52:53 +0000
+++ b/storage/ndb/src/ndbapi/NdbOperationExec.cpp	2008-08-26 14:05:01 +0000
@@ -102,55 +102,16 @@
     }//while
   }
 
+  /* Todo : Consider calling NdbOperation::postExecuteRelease()
+   * Ideally it should be called outside TP mutex, so not added
+   * here yet
+   */
+
   theNdbCon->OpSent();
   return tSignalCount;
 }//NdbOperation::doSend()
 
 
-/** 
- * SignalSectionIterator
- *
- * This is an implementation of GenericSectionIterator 
- * that uses chained NdbApiSignal objects to store a 
- * signal section.
- * The iterator is used by the transporter at signal
- * send time to obtain all of the relevant words for the
- * signal section
- */
-class SignalSectionIterator: public GenericSectionIterator
-{
-private :
-  NdbApiSignal* firstSignal;
-  NdbApiSignal* currentSignal;
-public :
-  SignalSectionIterator(NdbApiSignal* signal)
-  {
-    firstSignal= currentSignal= signal;
-  }
-
-  ~SignalSectionIterator()
-  {};
-  
-  void reset()
-  {
-    /* Reset iterator */
-    currentSignal= firstSignal;
-  }
-
-  Uint32* getNextWords(Uint32& sz)
-  {
-    if (likely(currentSignal != NULL))
-    {
-      NdbApiSignal* signal= currentSignal;
-      currentSignal= currentSignal->next();
-      sz= signal->getLength();
-      return signal->getDataPtrSend();
-    }
-    sz= 0;
-    return NULL;
-  }
-};
-
 int
 NdbOperation::doSendNdbRecord(int aNodeId)
 {
@@ -710,8 +671,6 @@
                                     Uint64 aTransId)
 {
   char buf[NdbRecord::Attr::SHRINK_VARCHAR_BUFFSIZE];
-  Uint32 *keyInfoPtr, *attrInfoPtr;
-  Uint32 remain;
   int res;
   Uint32 no_disk_flag;
   Uint32 *attrinfo_section_sizes_ptr= NULL;
@@ -732,8 +691,9 @@
   /* No KeyInfo goes in the TCKEYREQ signal - it all goes into 
    * a separate KeyInfo section
    */
-  keyInfoPtr= NULL;
-  remain= 0;
+  assert(theTCREQ->next() == NULL);
+  theKEYINFOptr= NULL;
+  keyInfoRemain= 0;
 
   /* Fill in keyinfo */
   if (!key_rec)
@@ -742,8 +702,7 @@
     /* i.e. lock takeover */
     tcKeyReq->tableId= attr_rec->tableId;
     tcKeyReq->tableSchemaVersion= attr_rec->tableVersion;
-    res= insertKEYINFO_NdbRecord(aTC_ConnectPtr, aTransId, key_row,
-                                 m_keyinfo_length*4, &keyInfoPtr, &remain);
+    res= insertKEYINFO_NdbRecord(key_row, m_keyinfo_length*4);
     if (res)
       return res;
   }
@@ -790,8 +749,7 @@
         setErrorCodeAbort(4209);
         return -1;
       }
-      res= insertKEYINFO_NdbRecord(aTC_ConnectPtr, aTransId,
-                                   src, length, &keyInfoPtr, &remain);
+      res= insertKEYINFO_NdbRecord(src, length);
       if (res)
         return res;
     }
@@ -810,8 +768,9 @@
   /* All ATTRINFO goes into a separate ATTRINFO section - none is placed
    * into the TCKEYREQ signal
    */
-  remain= 0;
-  attrInfoPtr= NULL;
+  assert(theFirstATTRINFO == NULL);
+  attrInfoRemain= 0;
+  theATTRINFOptr= NULL;
 
   no_disk_flag= m_no_disk_flag;
 
@@ -833,15 +792,13 @@
     sizes[3] = 0;               // Final read size
     sizes[4] = 0;               // Subroutine size
 
-    res = insertATTRINFOData_NdbRecord(aTC_ConnectPtr, aTransId,
-                                       (const char *)sizes,
-                                       sizeof(sizes),
-                                       &attrInfoPtr, &remain);
+    res = insertATTRINFOData_NdbRecord((const char *)sizes,
+                                       sizeof(sizes));
     if (res)
       return res;
 
     /* So that we can go back to set the actual sizes later... */
-    attrinfo_section_sizes_ptr= (attrInfoPtr - 
+    attrinfo_section_sizes_ptr= (theATTRINFOptr - 
                                  AttrInfo::SectionSizeInfoLength);
 
   }
@@ -894,11 +851,8 @@
 
       if (all)
       {
-        res= insertATTRINFOHdr_NdbRecord(aTC_ConnectPtr, aTransId,
-                                         AttributeHeader::READ_ALL,
-                                         requestedCols,
-                                         &attrInfoPtr,
-                                         &remain);
+        res= insertATTRINFOHdr_NdbRecord(AttributeHeader::READ_ALL,
+                                         requestedCols);
         if (res)
           return res;
       }
@@ -907,19 +861,13 @@
         /* How many bitmask words are significant? */
         Uint32 sigBitmaskWords= (maxAttrId>>5) + 1;
         
-        res= insertATTRINFOHdr_NdbRecord(aTC_ConnectPtr, aTransId,
-                                         AttributeHeader::READ_PACKED,
-                                         sigBitmaskWords << 2,
-                                         &attrInfoPtr,
-                                         &remain);
+        res= insertATTRINFOHdr_NdbRecord(AttributeHeader::READ_PACKED,
+                                         sigBitmaskWords << 2);
         if (res)
           return res;
         
-        res= insertATTRINFOData_NdbRecord(aTC_ConnectPtr, aTransId,
-                                          (const char*) &readMask.rep.data[0],
-                                          sigBitmaskWords << 2,
-                                          &attrInfoPtr,
-                                          &remain);
+        res= insertATTRINFOData_NdbRecord((const char*) &readMask.rep.data[0],
+                                          sigBitmaskWords << 2);
         if (res)
           return res;
       }
@@ -933,9 +881,7 @@
     const NdbRecAttr *ra= theReceiver.theFirstRecAttr;
     while (ra)
     {
-      res= insertATTRINFOHdr_NdbRecord(aTC_ConnectPtr, aTransId,
-                                       ra->attrId(), 0,
-                                       &attrInfoPtr, &remain);
+      res= insertATTRINFOHdr_NdbRecord(ra->attrId(), 0);
       if(res)
         return res;
       ra= ra->next();
@@ -952,14 +898,10 @@
      * 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);
+    res= insertATTRINFOHdr_NdbRecord(AttributeHeader::ANY_VALUE, 4);
     if(res)
       return res;
-    res= insertATTRINFOData_NdbRecord(aTC_ConnectPtr, aTransId,
-                                      (const char *)(&m_any_value), 4,
-                                      &attrInfoPtr, &remain);
+    res= insertATTRINFOData_NdbRecord((const char *)(&m_any_value), 4);
     if(res)
       return res;
   }
@@ -975,10 +917,8 @@
       code->m_first_sub_instruction_pos :
       code->m_instructions_length;
 
-    res = insertATTRINFOData_NdbRecord(aTC_ConnectPtr, aTransId,
-                                       (const char *)code->m_buffer,
-                                       mainProgramWords << 2,
-                                       &attrInfoPtr, &remain);
+    res = insertATTRINFOData_NdbRecord((const char *)code->m_buffer,
+                                       mainProgramWords << 2);
 
     if (res)
       return res;
@@ -1074,16 +1014,12 @@
         }
       } // if Blob or Bitfield
 
-      res= insertATTRINFOHdr_NdbRecord(aTC_ConnectPtr, aTransId,
-                                       attrId, length,
-                                       &attrInfoPtr, &remain);
+      res= insertATTRINFOHdr_NdbRecord(attrId, length);
       if(res)
         return res;
       if (length > 0)
       {
-        res= insertATTRINFOData_NdbRecord(aTC_ConnectPtr, aTransId,
-                                          data, length,
-                                          &attrInfoPtr, &remain);
+        res= insertATTRINFOData_NdbRecord(data, length);
         if(res)
           return res;
       }
@@ -1124,17 +1060,13 @@
         }       
 
         // Add ATTRINFO
-        res= insertATTRINFOHdr_NdbRecord(aTC_ConnectPtr, aTransId,
-                                         extraCol->getAttrId(), length,
-                                         &attrInfoPtr, &remain);
+        res= insertATTRINFOHdr_NdbRecord(extraCol->getAttrId(), length);
         if(res)
           return res;
 
         if(length>0)
         {
-          res=insertATTRINFOData_NdbRecord(aTC_ConnectPtr, aTransId,
-                                           (char*)pvalue, length,
-                                           &attrInfoPtr, &remain);
+          res=insertATTRINFOData_NdbRecord((char*)pvalue, length);
           if(res)
             return res;
         }
@@ -1153,14 +1085,10 @@
     /* Handle setAnyValue() for all cases except delete */
     if (m_use_any_value)
     {
-      res= insertATTRINFOHdr_NdbRecord(aTC_ConnectPtr, aTransId,
-                                       AttributeHeader::ANY_VALUE, 4,
-                                       &attrInfoPtr, &remain);
+      res= insertATTRINFOHdr_NdbRecord(AttributeHeader::ANY_VALUE, 4);
       if(res)
         return res;
-      res= insertATTRINFOData_NdbRecord(aTC_ConnectPtr, aTransId,
-                                        (const char *)(&m_any_value), 4,
-                                        &attrInfoPtr, &remain);
+      res= insertATTRINFOData_NdbRecord((const char *)(&m_any_value), 4);
       if(res)
         return res;
     }
@@ -1193,10 +1121,8 @@
 
       assert(subroutineWords > 0);
 
-      res = insertATTRINFOData_NdbRecord(aTC_ConnectPtr, aTransId,
-                                         (const char *)subroutineStart,
-                                         subroutineWords << 2,
-                                         &attrInfoPtr, &remain);
+      res = insertATTRINFOData_NdbRecord((const char *)subroutineStart,
+                                         subroutineWords << 2);
 
       if (res)
         return res;
@@ -1317,8 +1243,7 @@
   Return 0 on success, -1 on error.
 */
 int
-NdbOperation::allocKeyInfo(Uint32 connectPtr, Uint64 transId,
-                           Uint32 **dstPtr, Uint32 *remain)
+NdbOperation::allocKeyInfo()
 {
   NdbApiSignal *tSignal;
 
@@ -1329,18 +1254,18 @@
     return -1;
   }
   tSignal->next(NULL);
-  if (theTCREQ->next() != NULL)
+  if (theRequest->next() != NULL)
   {
     theLastKEYINFO->setLength(NdbApiSignal::MaxSignalWords);
     theLastKEYINFO->next(tSignal);
   }
   else
   {
-    theTCREQ->next(tSignal);
+    theRequest->next(tSignal);
   }
   theLastKEYINFO= tSignal;
-  *remain= NdbApiSignal::MaxSignalWords;
-  *dstPtr= tSignal->getDataPtrSend();
+  keyInfoRemain= NdbApiSignal::MaxSignalWords;
+  theKEYINFOptr= tSignal->getDataPtrSend();
 
   return 0;
 }
@@ -1352,8 +1277,7 @@
   Return 0 on success, -1 on error.
 */
 int
-NdbOperation::allocAttrInfo(Uint32 connectPtr, Uint64 transId,
-                            Uint32 **dstPtr, Uint32 *remain)
+NdbOperation::allocAttrInfo()
 {
   NdbApiSignal *tSignal;
 
@@ -1374,87 +1298,79 @@
     theFirstATTRINFO= tSignal;
   }
   theCurrentATTRINFO= tSignal;
-  *remain= NdbApiSignal::MaxSignalWords;
-  *dstPtr= tSignal->getDataPtrSend();
+  attrInfoRemain= NdbApiSignal::MaxSignalWords;
+  theATTRINFOptr= tSignal->getDataPtrSend();
 
   return 0;
 }
 
 int
-NdbOperation::insertKEYINFO_NdbRecord(Uint32 connectPtr,
-                                      Uint64 transId,
-                                      const char *value,
-                                      Uint32 size,
-                                      Uint32 **dstPtr,
-                                      Uint32 *remain)
+NdbOperation::insertKEYINFO_NdbRecord(const char *value,
+                                      Uint32 byteSize)
 {
   /* Words are added to a list of signal objects linked from 
-   * theTCREQ->next()
+   * theRequest->next()
    * The list of objects is then used to form the KeyInfo
-   * section of the TCKEYREQ long signal
+   * section of the TCKEYREQ/TCINDXREQ/SCANTABREQ long signal
    * No separate KeyInfo signal train is sent.
    */
-  theTupKeyLen+= (size+3)/4;
+  theTupKeyLen+= (byteSize+3)/4;
 
-  while (size > *remain*4)
+  while (byteSize > keyInfoRemain*4)
   {
     /* Need to link in extra objects */
-    if (*remain)
+    if (keyInfoRemain)
     {
       /* Fill remaining words in this object */
-      assert(*dstPtr != NULL);
-      memcpy(*dstPtr, value, *remain*4);
-      value+= *remain*4;
-      size-= *remain*4;
+      assert(theKEYINFOptr != NULL);
+      memcpy(theKEYINFOptr, value, keyInfoRemain*4);
+      value+= keyInfoRemain*4;
+      byteSize-= keyInfoRemain*4;
     }
 
     /* Link new object in */
-    int res= allocKeyInfo(connectPtr, transId, dstPtr, remain);
+    int res= allocKeyInfo();
     if(res)
       return res;
   }
 
-  assert(theTCREQ->next() != NULL);
+  assert(theRequest->next() != NULL);
   assert(theLastKEYINFO != NULL);
 
   /* Remaining words fit in this object */
-  assert(*dstPtr != NULL);
-  memcpy(*dstPtr, value, size);
-  if((size%4) != 0)
-    memset(((char *)*dstPtr)+size, 0, 4-(size%4));
-  Uint32 sizeInWords= (size+3)/4;
-  *dstPtr+= sizeInWords;
-  *remain-= sizeInWords;
+  assert(theKEYINFOptr != NULL);
+  memcpy(theKEYINFOptr, value, byteSize);
+  if((byteSize%4) != 0)
+    memset(((char *)theKEYINFOptr)+byteSize, 0, 4-(byteSize%4));
+  Uint32 sizeInWords= (byteSize+3)/4;
+  theKEYINFOptr+= sizeInWords;
+  keyInfoRemain-= sizeInWords;
 
   theLastKEYINFO->setLength(NdbApiSignal::MaxSignalWords 
-                            - *remain);
+                            - keyInfoRemain);
 
   return 0;
 }
 
 int
-NdbOperation::insertATTRINFOHdr_NdbRecord(Uint32 connectPtr,
-                                          Uint64 transId,
-                                          Uint32 attrId,
-                                          Uint32 attrLen,
-                                          Uint32 **dstPtr,
-                                          Uint32 *remain)
+NdbOperation::insertATTRINFOHdr_NdbRecord(Uint32 attrId,
+                                          Uint32 attrLen)
 {
   /* Words are added to a list of Signal objects pointed to
    * by theFirstATTRINFO
    * This list is then used to form the ATTRINFO
-   * section of the TCKEYREQ long signal
+   * section of the TCKEYREQ/TCINDXREQ/SCANTABREQ long signal
    * No ATTRINFO signal train is sent.
    */
 
   theTotalCurrAI_Len++;
 
-  if (! *remain)
+  if (! attrInfoRemain)
   {
     /* Need to link in an extra object to store this
      * word
      */
-    int res= allocAttrInfo(connectPtr, transId, dstPtr, remain);
+    int res= allocAttrInfo();
     if (res)
       return res;
   }
@@ -1464,24 +1380,20 @@
   AttributeHeader::init(&ah, attrId, attrLen);
   assert(theFirstATTRINFO != NULL);
   assert(theCurrentATTRINFO != NULL);
-  assert(dstPtr != NULL);
+  assert(theATTRINFOptr != NULL);
 
-  *(*dstPtr)++= ah;
-  (*remain)--;
+  *(theATTRINFOptr++)= ah;
+  attrInfoRemain--;
 
   theCurrentATTRINFO->setLength(NdbApiSignal::MaxSignalWords
-                                - *remain);
+                                - attrInfoRemain);
 
   return 0;
 }
 
 int
-NdbOperation::insertATTRINFOData_NdbRecord(Uint32 connectPtr,
-                                           Uint64 transId,
-                                           const char *value,
-                                           Uint32 size,
-                                           Uint32 **dstPtr,
-                                           Uint32 *remain)
+NdbOperation::insertATTRINFOData_NdbRecord(const char *value,
+                                           Uint32 byteSize)
 {
   /* Words are added to a list of Signal objects pointed to
    * by theFirstATTRINFO
@@ -1489,20 +1401,20 @@
    * section of the TCKEYREQ long signal
    * No ATTRINFO signal train is sent.
    */
-  theTotalCurrAI_Len+= (size+3)/4;
+  theTotalCurrAI_Len+= (byteSize+3)/4;
 
-  while (size > *remain*4)
+  while (byteSize > attrInfoRemain*4)
   {
     /* Need to link in extra objects */
-    if (*remain)
+    if (attrInfoRemain)
     {
       /* Fill remaining space in current object */
-      memcpy(*dstPtr, value, *remain*4);
-      value+= *remain*4;
-      size-= *remain*4;
+      memcpy(theATTRINFOptr, value, attrInfoRemain*4);
+      value+= attrInfoRemain*4;
+      byteSize-= attrInfoRemain*4;
     }
 
-    int res= allocAttrInfo(connectPtr, transId, dstPtr, remain);
+    int res= allocAttrInfo();
     if (res)
       return res;
   }
@@ -1510,17 +1422,17 @@
   /* Remaining words fit in current signal */
   assert(theFirstATTRINFO != NULL);
   assert(theCurrentATTRINFO != NULL);
-  assert(*dstPtr != NULL);
+  assert(theATTRINFOptr != NULL);
 
-  memcpy(*dstPtr, value, size);
-  if((size%4) != 0)
-    memset(((char *)*dstPtr)+size, 0, 4-(size%4));
-  Uint32 sizeInWords= (size+3)/4;
-  *dstPtr+= sizeInWords;
-  *remain-= sizeInWords;
+  memcpy(theATTRINFOptr, value, byteSize);
+  if((byteSize%4) != 0)
+    memset(((char *)theATTRINFOptr)+byteSize, 0, 4-(byteSize%4));
+  Uint32 sizeInWords= (byteSize+3)/4;
+  theATTRINFOptr+= sizeInWords;
+  attrInfoRemain-= sizeInWords;
 
   theCurrentATTRINFO->setLength(NdbApiSignal::MaxSignalWords 
-                                - *remain);
+                                - attrInfoRemain);
 
   return 0;
 }

=== modified file 'storage/ndb/src/ndbapi/NdbReceiver.cpp'
--- a/storage/ndb/src/ndbapi/NdbReceiver.cpp	2008-04-04 17:36:54 +0000
+++ b/storage/ndb/src/ndbapi/NdbReceiver.cpp	2008-08-26 14:05:01 +0000
@@ -132,6 +132,8 @@
 
   Hm, there are some magic overhead numbers (4 bytes/attr, 32 bytes/row) here,
   would be nice with some explanation on how these numbers were derived.
+
+  TODO : Check whether these numbers need to be revised w.r.t. read packed
 */
 void
 NdbReceiver::calculate_batch_size(Uint32 key_size,

=== modified file 'storage/ndb/src/ndbapi/NdbScanOperation.cpp'
--- a/storage/ndb/src/ndbapi/NdbScanOperation.cpp	2008-08-22 13:12:07 +0000
+++ b/storage/ndb/src/ndbapi/NdbScanOperation.cpp	2008-08-26 14:05:01 +0000
@@ -137,8 +137,6 @@
   /* Handle old API-defined scan getValue(s) */
   assert(m_scanUsingOldApi);
 
-  // TODO : Is it valid for an old-Api scan to have no extra
-  // getValues()?
   if (theReceiver.theFirstRecAttr != NULL) 
   {
     /* theReceiver has a list of RecAttrs which the user
@@ -149,19 +147,19 @@
      * Once these are added to the signal train, all other handling
      * is exactly the same as for normal NdbRecord 'extra GetValues'
      */
-    NdbRecAttr* recAttrToRead = theReceiver.theFirstRecAttr;
+    const NdbRecAttr* recAttrToRead = theReceiver.theFirstRecAttr;
 
     while(recAttrToRead != NULL)
     {
       int res;
-      Uint32 ah;
-      AttributeHeader::init(&ah, recAttrToRead->theAttrId, 0);
-      res= insertATTRINFO(ah);
-      if (res==-1)
+      res= insertATTRINFOHdr_NdbRecord(recAttrToRead->theAttrId, 0);
+      if (unlikely(res == -1))
         return -1;
-      theInitialReadSize= theTotalCurrAI_Len - AttrInfo::SectionSizeInfoLength;
       recAttrToRead= recAttrToRead->next();
-    } 
+    }
+ 
+    theInitialReadSize= theTotalCurrAI_Len - AttrInfo::SectionSizeInfoLength;
+
   }
 
   return 0;
@@ -190,8 +188,8 @@
     code->m_first_sub_instruction_pos :
     code->m_instructions_length;
   
-  int res = insertATTRINFOloop(code->m_buffer,
-                               mainProgramWords);
+  int res = insertATTRINFOData_NdbRecord((const char*)code->m_buffer,
+                                         mainProgramWords << 2);
   if (res == 0)
   {
     /* Add subroutines, if we have any */
@@ -206,8 +204,8 @@
         code->m_instructions_length -
         code->m_first_sub_instruction_pos;
       
-      res = insertATTRINFOloop(subroutineStart,
-                               subroutineWords);
+      res = insertATTRINFOData_NdbRecord((const char*) subroutineStart,
+                                         subroutineWords << 2);
     }
 
     /* Update signal section lengths */
@@ -377,24 +375,21 @@
    */
   if (columnCount > 0)
   {
-    Uint32 ah;
     bool all= (columnCount == m_currentTable->m_columns.size());
     
     if (all)
-    {
-      AttributeHeader::init(&ah, AttributeHeader::READ_ALL, columnCount);
-      result= insertATTRINFO(ah);
-    }
+      result= insertATTRINFOHdr_NdbRecord(AttributeHeader::READ_ALL, 
+                                          columnCount);
     else
     {
       /* How many bitmask words are significant? */
       Uint32 sigBitmaskWords= (maxAttrId>>5) + 1;
       
-      AttributeHeader::init(&ah, AttributeHeader::READ_PACKED, 4*sigBitmaskWords);
-      result= insertATTRINFO(ah); // Header
+      result= insertATTRINFOHdr_NdbRecord(AttributeHeader::READ_PACKED, 
+                                          sigBitmaskWords << 2);
       if (result != -1)
-        result= insertATTRINFOloop(&readMask.rep.data[0], 
-                                   sigBitmaskWords); // Bitmask
+        result= insertATTRINFOData_NdbRecord((const char*) &readMask.rep.data[0],
+                                             sigBitmaskWords << 2); // Bitmask
     }
   }
 
@@ -744,6 +739,13 @@
     return -1;
   }
 
+  /* We need to get a ptr to the first word of this
+   * range so that we can set the total length of the range 
+   * (and range num) at the end of writing out the range.
+   */
+  Uint32* firstRangeWord= NULL;
+  const Uint32 keyLenBeforeRange= theTupKeyLen;
+
   for (j= 0; j<key_count; j++)
   {
     Uint32 bound_type;
@@ -754,7 +756,7 @@
       bound_type= bound.low_inclusive  || j+1 < bound.low_key_count ?
         BoundLE : BoundLT;
       ndbrecord_insert_bound(key_record, key_record->key_indexes[j],
-                             bound.low_key, bound_type);
+                             bound.low_key, bound_type, firstRangeWord);
     }
     /* If key is part of upper bound */
     if (bound.high_key && j<bound.high_key_count)
@@ -763,21 +765,21 @@
       bound_type= bound.high_inclusive  || j+1 < bound.high_key_count ?
         BoundGE : BoundGT;
       ndbrecord_insert_bound(key_record, key_record->key_indexes[j],
-                             bound.high_key, bound_type);
+                             bound.high_key, bound_type, firstRangeWord);
     }
   }
 
-  /* Set the length of this bound
-   * Length = bound end - bound start
+  /* Set the length of this range
+   * Length = TupKeyLen@range end - TupKeyLen@ range start
    * Pack into Uint32 with range no and bound type as described 
    * in KeyInfo.hpp
    */
-  bound_head= *m_first_bound_word;
+  assert(firstRangeWord != NULL);
+  
+  bound_head= *firstRangeWord;
   bound_head|=
-    (theTupKeyLen - m_this_bound_start) << 16 | (range_no << 4);
-  *m_first_bound_word= bound_head;
-  m_first_bound_word= theKEYINFOptr + theTotalNrOfKeyWordInSignal;
-  m_this_bound_start= theTupKeyLen;
+    (theTupKeyLen - keyLenBeforeRange) << 16 | (range_no << 4);
+  *firstRangeWord= bound_head;
 
   /*
     Now check if the range bounds a single distribution key. If so, we need
@@ -1011,8 +1013,9 @@
   }
   
   if (rangeScan && (scan_flags & SF_OrderBy))
-    parallel = fragCount; // Note we assume fragcount of base table==
-                          // fragcount of index.
+    parallel = fragCount; /* Frag count of ordered index ==
+                           * Frag count of base table
+                           */
   
   theParallelism = parallel;    
   
@@ -1021,7 +1024,6 @@
     return -1;
   }
   
-  theSCAN_TABREQ = (!theSCAN_TABREQ ? theNdb->getSignal() : theSCAN_TABREQ);
   if (theSCAN_TABREQ == NULL) {
     setErrorCodeAbort(4000);
     return -1;
@@ -1034,6 +1036,7 @@
   req->tableSchemaVersion = m_accessTable->m_version;
   req->storedProcId = 0xFFFF;
   req->buddyConPtr = theNdbCon->theBuddyConPtr;
+  req->spare= 0;
   req->first_batch_size = batch; // Save user specified batch size
   
   Uint32 reqInfo = 0;
@@ -1050,15 +1053,13 @@
   req->transId1 = (Uint32) transId;
   req->transId2 = (Uint32) (transId >> 32);
 
-  NdbApiSignal* tSignal = theSCAN_TABREQ->next();
-  if(!tSignal)
-  {
-    theSCAN_TABREQ->next(tSignal = theNdb->getSignal());
-  }
+  assert(theSCAN_TABREQ->next() == NULL);
+  NdbApiSignal* tSignal= theNdb->getSignal();
+  theSCAN_TABREQ->next(tSignal);
   theLastKEYINFO = tSignal;
   
-  tSignal->setSignal(GSN_KEYINFO);
-  theKEYINFOptr = ((KeyInfo*)tSignal->getDataPtrSend())->keyData;
+  theKEYINFOptr= tSignal->getDataPtrSend();
+  keyInfoRemain= NdbApiSignal::MaxSignalWords;
   theTotalNrOfKeyWordInSignal= 0;
 
   getFirstATTRINFOScan();
@@ -1244,7 +1245,7 @@
 }
 
 /*****************************************************************************
- * int getFirstATTRINFOScan( U_int32 aData )
+ * int getFirstATTRINFOScan()
  *
  * Return Value:  Return 0:   Successful
  *                Return -1:  All other cases
@@ -1265,10 +1266,11 @@
     setErrorCodeAbort(4000);      
     return -1;    
   }
-  tSignal->setSignal(m_attrInfoGSN);
 
-  theAI_LenInCurrAI = AttrInfo::HeaderLength + AttrInfo::SectionSizeInfoLength;
-  theATTRINFOptr = &tSignal->getDataPtrSend()[8];
+  theAI_LenInCurrAI = AttrInfo::SectionSizeInfoLength;
+  theATTRINFOptr = &tSignal->getDataPtrSend()[AttrInfo::SectionSizeInfoLength];
+  attrInfoRemain= NdbApiSignal::MaxSignalWords - AttrInfo::SectionSizeInfoLength;
+  tSignal->setLength(AttrInfo::SectionSizeInfoLength);
   theFirstATTRINFO = tSignal;
   theCurrentATTRINFO = tSignal;
   theCurrentATTRINFO->next(NULL);
@@ -1831,12 +1833,6 @@
   /* All scans use NdbRecord at this stage */
   assert(m_attribute_record);
 
-  /* Some signal building code sets all intermediate ATTRINFOs to
-   * max length, and it's this line's job to set the correct
-   * value for the last signal
-   */
-  theCurrentATTRINFO->setLength(theAI_LenInCurrAI);
-
   /**
    * Prepare all receivers
    */
@@ -1864,7 +1860,7 @@
   /**
    * Set keyinfo, nodisk and distribution key flags in 
    * ScanTabReq
-   *  (Always keyinfo when using blobs)
+   *  (Always request keyinfo when using blobs)
    */
   Uint32 reqInfo = req->requestInfo;
   ScanTabReq::setKeyinfoFlag(reqInfo, keyInfo);
@@ -1879,8 +1875,9 @@
   /* All scans use NdbRecord internally */
   assert(theStatus == UseNdbRecord);
   
+  /* Calculate the extra bytes needed per row for extra getValues */
   Uint32 extra_size= 0;
-  if (unlikely(theReceiver.theFirstRecAttr != NULL))
+  if (theReceiver.theFirstRecAttr != NULL)
     extra_size= calcGetValueSize();
   
   assert(theParallelism > 0);
@@ -1918,11 +1915,12 @@
 NdbScanOperation::doSendSetAISectionSizes()
 {
   // Set the scan AI section sizes.
-  theFirstATTRINFO->setData(theInitialReadSize, 4);
-  theFirstATTRINFO->setData(theInterpretedSize, 5);
-  theFirstATTRINFO->setData(0, 6); // Update size
-  theFirstATTRINFO->setData(0, 7); // Final read size
-  theFirstATTRINFO->setData(theSubroutineSize, 8); 
+  Uint32* sectionSizesPtr= theFirstATTRINFO->getDataPtrSend();
+  *sectionSizesPtr++ = theInitialReadSize;
+  *sectionSizesPtr++ = theInterpretedSize;
+  *sectionSizesPtr++ = 0; // Update size 
+  *sectionSizesPtr++ = 0; // Final read size
+  *sectionSizesPtr   = theSubroutineSize;
 
   return 0;
 }
@@ -1944,6 +1942,10 @@
   return size;
 }
 
+
+
+
+
 /*****************************************************************************
 int doSendScan()
 
@@ -1955,9 +1957,6 @@
 int
 NdbScanOperation::doSendScan(int aProcessorId)
 {
-  Uint32 tSignalCount = 0;
-  NdbApiSignal* tSignal;
- 
   if (theInterpretIndicator != 1 ||
       (theOperationType != OpenScanRequest &&
        theOperationType != OpenRangeScanRequest)) {
@@ -1966,75 +1965,53 @@
   }
   
   assert(theSCAN_TABREQ != NULL);
-  tSignal = theSCAN_TABREQ;
-  
-  Uint32 tupKeyLen = theTupKeyLen;
-  Uint32 aTC_ConnectPtr = theNdbCon->theTCConPtr;
-  Uint64 transId = theNdbCon->theTransactionId;
-  
-  /**
-   * Update the "attribute info length in words" in SCAN_TABREQ before 
-   * sending it. This could not be done before as it is possible to 
-   * add bounds to an index scan after it is defined using 
-   * scanIndex.
-   */
-  ScanTabReq * const req = CAST_PTR(ScanTabReq, tSignal->getDataPtrSend());
+  
+  /* Check that we don't have too much AttrInfo */
   if (unlikely(theTotalCurrAI_Len > ScanTabReq::MaxTotalAttrInfo)) {
     setErrorCode(4257);
     return -1;
   }
-  req->attrLenKeyLen = (tupKeyLen << 16) | theTotalCurrAI_Len;
+
+  /* SCANTABREQ always has 2 mandatory sections and an optional
+   * third section
+   * Section 0 : List of receiver Ids NDBAPI has allocated 
+   *             for the scan
+   * Section 1 : ATTRINFO section
+   * Section 2 : Optional KEYINFO section
+   */
+  GenericSectionPtr secs[3];
+  LinearSectionIterator receiverIdIterator(m_prepared_receivers,
+                                           theParallelism);
+  SignalSectionIterator attrInfoIter(theFirstATTRINFO);
+  SignalSectionIterator keyInfoIter(theSCAN_TABREQ->next());
+
+  secs[0].sectionIter= &receiverIdIterator;
+  secs[0].sz= theParallelism;
+
+  secs[1].sectionIter= &attrInfoIter;
+  secs[1].sz= theTotalCurrAI_Len;
+
+  Uint32 numSections= 2;
+
+  if (theTupKeyLen)
+  {
+    secs[2].sectionIter= &keyInfoIter;
+    secs[2].sz= theTupKeyLen;
+    numSections= 3;
+  }
 
   TransporterFacade *tp = theNdb->theImpl->m_transporter_facade;
-  LinearSectionPtr ptr[3];
-  ptr[0].p = m_prepared_receivers;
-  ptr[0].sz = theParallelism;
-  if (tp->sendSignal(tSignal, aProcessorId, ptr, 1) == -1) {
+  
+  /* Send Fragmented as SCAN_TABREQ can be large */
+  if (tp->sendFragmentedSignal(theSCAN_TABREQ, 
+                               aProcessorId, 
+                               &secs[0], 
+                               numSections) == -1)
+  {
     setErrorCode(4002);
     return -1;
-  } 
+  }
 
-  if (tupKeyLen > 0){
-    // must have at least one signal since it contains attrLen for bounds
-    assert(theLastKEYINFO != NULL);
-    tSignal = theLastKEYINFO;
-    tSignal->setLength(KeyInfo::HeaderLength + theTotalNrOfKeyWordInSignal);
-    
-    assert(theSCAN_TABREQ->next() != NULL);
-    tSignal = theSCAN_TABREQ->next();
-    
-    NdbApiSignal* last;
-    do {
-      KeyInfo * keyInfo = CAST_PTR(KeyInfo, tSignal->getDataPtrSend());
-      keyInfo->connectPtr = aTC_ConnectPtr;
-      keyInfo->transId[0] = Uint32(transId);
-      keyInfo->transId[1] = Uint32(transId >> 32);
-      
-      if (tp->sendSignal(tSignal,aProcessorId) == -1){
-        setErrorCode(4002);
-        return -1;
-      }
-      
-      tSignalCount++;
-      last = tSignal;
-      tSignal = tSignal->next();
-    } while(last != theLastKEYINFO);
-  }
-  
-  tSignal = theFirstATTRINFO;
-  while (tSignal != NULL) {
-    AttrInfo * attrInfo = CAST_PTR(AttrInfo, tSignal->getDataPtrSend());
-    attrInfo->connectPtr = aTC_ConnectPtr;
-    attrInfo->transId[0] = Uint32(transId);
-    attrInfo->transId[1] = Uint32(transId >> 32);
-    
-    if (tp->sendSignal(tSignal,aProcessorId) == -1){
-      setErrorCode(4002);
-      return -1;
-    }
-    tSignalCount++;
-    tSignal = tSignal->next();
-  }    
   theStatus = WaitResponse;  
 
   m_curr_row = 0;
@@ -2045,7 +2022,7 @@
     m_api_receivers_count = theParallelism;
   }
   
-  return tSignalCount;
+  return 1; // 1 signal sent
 }//NdbOperation::doSendScan()
 
 
@@ -2395,17 +2372,16 @@
 {
   DBUG_ENTER("NdbScanOperation::getValue_NdbRecord_scan");
   int res;
-  Uint32 ah;
   NdbRecAttr *ra;
   DBUG_PRINT("info", ("Column: %u", attrInfo->m_attrId));
 
   m_no_disk_flag &= 
     (attrInfo->m_storageType == NDB_STORAGETYPE_MEMORY);
 
-  AttributeHeader::init(&ah, attrInfo->m_attrId, 0);
-  res= insertATTRINFO(ah);
+  res= insertATTRINFOHdr_NdbRecord(attrInfo->m_attrId, 0);
   if (res==-1)
     DBUG_RETURN(NULL);
+
   theInitialReadSize= theTotalCurrAI_Len - AttrInfo::SectionSizeInfoLength;
   ra= theReceiver.getValue(attrInfo, aValue);
   if (!ra)
@@ -2835,64 +2811,14 @@
 }
 
 
-/**
- * insertBOUNDS
- * Helper for ndbrecord_insert_bound, copying data into the
- * signal train and linking in new signals as required.
- */
-int
-NdbIndexScanOperation::insertBOUNDS(Uint32 * data, Uint32 sz){
-  Uint32 len;
-  Uint32 remaining = KeyInfo::DataLength - theTotalNrOfKeyWordInSignal;
-  Uint32 * dst = theKEYINFOptr + theTotalNrOfKeyWordInSignal;
-  do {
-    len = (sz < remaining ? sz : remaining);
-    memcpy(dst, data, 4 * len);
-    
-    if(sz >= remaining){
-      /* Need to spill data into another signal */
-      NdbApiSignal* tCurr = theLastKEYINFO;
-      tCurr->setLength(KeyInfo::MaxSignalLength);
-      NdbApiSignal* tSignal = tCurr->next();
-      if(tSignal)
-        ;
-      else if((tSignal = theNdb->getSignal()) != 0)
-      {
-        /* Link new signal into train and set type */
-        tCurr->next(tSignal);
-        tSignal->setSignal(GSN_KEYINFO);
-      } else {
-        goto error;
-      }
-      theLastKEYINFO = tSignal;
-      theKEYINFOptr = dst = ((KeyInfo*)tSignal->getDataPtrSend())->keyData;
-      remaining = KeyInfo::DataLength;
-      sz -= len;
-      data += len;
-    } else {
-      len = (KeyInfo::DataLength - remaining) + len;
-      break;
-    }
-  } while(true);   
-  theTotalNrOfKeyWordInSignal = len;
-  return 0;
-
-error:
-  setErrorCodeAbort(4228);    // XXX wrong code
-  return -1;
-}
-
-
-
 int
 NdbIndexScanOperation::ndbrecord_insert_bound(const NdbRecord *key_record,
                                               Uint32 column_index,
                                               const char *row,
-                                              Uint32 bound_type)
+                                              Uint32 bound_type,
+                                              Uint32*& firstWordOfBound)
 {
   char buf[NdbRecord::Attr::SHRINK_VARCHAR_BUFFSIZE];
-  Uint32 currLen= theTotalNrOfKeyWordInSignal;
-  Uint32 remaining= KeyInfo::DataLength - currLen;
   const NdbRecord::Attr *column= &key_record->columns[column_index];
 
   bool is_null= column->is_null(row);
@@ -2918,49 +2844,32 @@
     }
   }
 
-  /* Insert attribute header. */
-  Uint32 tIndexAttrId= column->index_attrId;
-  Uint32 sizeInWords= (len + 3) / 4;
-  AttributeHeader ah(tIndexAttrId, len);
-  const Uint32 ahValue= ah.m_value;
-  const bool aligned= (UintPtr(aValue) & 3) == 0;
-
-  /*
-    The nobytes flag is false if there are extra padding bytes at the end,
-    which we need to zero out.
-  */
-  const bool nobytes= (len & 0x3) == 0;
-  const Uint32 totalLen= 2 + sizeInWords;
-  Uint32 tupKeyLen= theTupKeyLen;
-  if (remaining > totalLen && aligned && nobytes){
-    Uint32 * dst= theKEYINFOptr + currLen;
-    * dst ++ = bound_type;
-    * dst ++ = ahValue;
-    memcpy(dst, aValue, 4 * sizeInWords);
-    theTotalNrOfKeyWordInSignal= currLen + totalLen;
-  } else {
-    if(!aligned || !nobytes){
-      /* Space for Bound type, Attr header and (possibly max-sized)
-       * key column
-       */
-      Uint32 tempData[ KeyInfo::MaxWordsPerBoundColumn ];
-      if (len > sizeof(tempData))
-        len= sizeof(tempData);
-      tempData[0] = bound_type;
-      tempData[1] = ahValue;
-      tempData[2 + (len >> 2)] = 0;
-      memcpy(tempData+2, aValue, len);
-      insertBOUNDS(tempData, 2+sizeInWords);
-    } else {
-      /* No alignment or zeroing required, just
-       * need to spill into another signal */
-      Uint32 buf[2] = { bound_type, ahValue };
-      insertBOUNDS(buf, 2);
-      insertBOUNDS((Uint32*)aValue, sizeInWords);
-    }
-  }
-  theTupKeyLen= tupKeyLen + totalLen;
-
+  /* Add bound type */
+  if (unlikely(insertKEYINFO_NdbRecord((const char*) &bound_type, 
+                                       sizeof(Uint32))))
+  {
+    /* Some sort of allocation error */
+    setErrorCodeAbort(4000);
+    return -1;
+  }
+  
+  assert( theKEYINFOptr != NULL );
+  /* Grab ptr to first word of this bound if caller wants it */
+  if (firstWordOfBound == NULL)
+    firstWordOfBound= theKEYINFOptr - 1;
+
+  AttributeHeader ah(column->index_attrId, len);
+
+  /* Add AttrInfo header + data for bound */
+  if (unlikely(insertKEYINFO_NdbRecord((const char*) &ah.m_value, 
+                                       sizeof(Uint32)) ||
+               insertKEYINFO_NdbRecord((const char*) aValue, len) ))
+  {
+    /* Some sort of allocation error */
+    setErrorCodeAbort(4000);
+    return -1;
+  }
+  
   return 0;
 }
 
@@ -3020,9 +2929,8 @@
   if(!res && read_range_no)
   {
     m_read_range_no = 1;
-    Uint32 word = 0;
-    AttributeHeader::init(&word, AttributeHeader::RANGE_NO, 0);
-    if(insertATTRINFO(word) == -1)
+    if (insertATTRINFOHdr_NdbRecord(AttributeHeader::RANGE_NO, 
+                                    0) == -1)
       res = -1;
   }
   if (!res)
@@ -3052,8 +2960,7 @@
     /* Should always have NdbRecord at this point */
     assert (m_attribute_record);
   }
-  m_this_bound_start = 0;
-  m_first_bound_word = theKEYINFOptr;
+
   m_num_bounds = 0;
   m_previous_range_num = 0;
 

=== modified file 'storage/ndb/src/ndbapi/NdbTransaction.cpp'
--- a/storage/ndb/src/ndbapi/NdbTransaction.cpp	2008-08-06 15:39:54 +0000
+++ b/storage/ndb/src/ndbapi/NdbTransaction.cpp	2008-08-26 14:05:01 +0000
@@ -639,6 +639,8 @@
       if (tReturnCode == -1) {
         DBUG_VOID_RETURN;
       }//if
+      tcOp->postExecuteRelease(); // Release unneeded resources
+                                  // outside TP mutex
       tcOp = (NdbScanOperation*)tcOp->next();
     } // while
     m_theLastScanOperation->next(m_firstExecutedScanOp);

=== modified file 'storage/ndb/src/ndbapi/TransporterFacade.cpp'
--- a/storage/ndb/src/ndbapi/TransporterFacade.cpp	2008-08-12 09:47:08 +0000
+++ b/storage/ndb/src/ndbapi/TransporterFacade.cpp	2008-08-26 14:05:01 +0000
@@ -1090,14 +1090,247 @@
   return (ss == SEND_OK ? 0 : -1);
 }
 
-#define CHUNK_SZ NDB_SECTION_SEGMENT_SZ*64 // related to MAX_MESSAGE_SIZE
+/**
+ * FragmentedSectionIterator
+ * -------------------------
+ * This class acts as an adapter to a GenericSectionIterator
+ * instance, providing a sub-range iterator interface.
+ * It is used when long sections of a signal are fragmented
+ * across multiple actual signals - the user-supplied
+ * GenericSectionIterator is then adapted into a
+ * GenericSectionIterator that only returns a subset of
+ * the contained words for each signal fragment.
+ */
+class FragmentedSectionIterator: public GenericSectionIterator
+{
+private :
+  GenericSectionIterator* realIterator; /* Real underlying iterator */
+  Uint32 realIterWords;                 /* Total size of underlying */
+  Uint32 realCurrPos;                   /* Current pos in underlying */
+  Uint32 rangeStart;                    /* Sub range start in underlying */
+  Uint32 rangeLen;                      /* Sub range len in underlying */
+  Uint32 rangeRemain;                   /* Remaining words in underlying */
+  Uint32* lastReadPtr;                  /* Ptr to last chunk obtained from
+                                         * underlying */
+  Uint32 lastReadPtrLen;                /* Remaining words in last chunk
+                                         * obtained from underlying */
+public:
+  /* Constructor
+   * The instance is constructed with the sub-range set to be the
+   * full range of the underlying iterator
+   */
+  FragmentedSectionIterator(GenericSectionPtr ptr)
+  {
+    realIterator= ptr.sectionIter;
+    realIterWords= ptr.sz;
+    realCurrPos= 0;
+    rangeStart= 0;
+    rangeLen= rangeRemain= realIterWords;
+    lastReadPtr= NULL;
+    lastReadPtrLen= 0;
+    moveToPos(0);
+
+    assert(checkInvariants());
+  }
+
+private:
+  /** 
+   * checkInvariants
+   * These class invariants must hold true at all stable states
+   * of the iterator
+   */
+  bool checkInvariants()
+  {
+    assert( (realIterator != NULL) || (realIterWords == 0) );
+    assert( realCurrPos <= realIterWords );
+    assert( rangeStart <= realIterWords );
+    assert( (rangeStart+rangeLen) <= realIterWords);
+    assert( rangeRemain <= rangeLen );
+    
+    /* Can only have a null readptr if nothing is left */
+    assert( (lastReadPtr != NULL) || (rangeRemain == 0));
+
+    /* If we have a non-null readptr and some remaining 
+     * words the readptr must have some words
+     */
+    assert( (lastReadPtr == NULL) || 
+            ((rangeRemain == 0) || (lastReadPtrLen != 0)));
+    return true;
+  }
+
+  /**
+   * moveToPos
+   * This method is used when the iterator is reset(), to move
+   * to the start of the current sub-range.
+   * If the iterator is already in-position then this is efficient
+   * Otherwise, it has to reset() the underling iterator and
+   * advance it until the start position is reached.
+   */
+  void moveToPos(Uint32 pos)
+  {
+    assert(pos <= realIterWords);
+
+    if (pos < realCurrPos)
+    {
+      /* Need to reset, and advance from the start */
+      realIterator->reset();
+      realCurrPos= 0;
+      lastReadPtr= NULL;
+      lastReadPtrLen= 0;
+    }
+
+    if ((lastReadPtr == NULL) && 
+        (realIterWords != 0) &&
+        (pos != realIterWords))
+      lastReadPtr= realIterator->getNextWords(lastReadPtrLen);
+    
+    if (pos == realCurrPos)
+      return;
+
+    /* Advance until we get a chunk which contains the pos */
+    while (pos >= realCurrPos + lastReadPtrLen)
+    {
+      realCurrPos+= lastReadPtrLen;
+      lastReadPtr= realIterator->getNextWords(lastReadPtrLen);
+      assert(lastReadPtr != NULL);
+    }
+
+    const Uint32 chunkOffset= pos - realCurrPos;
+    lastReadPtr+= chunkOffset;
+    lastReadPtrLen-= chunkOffset;
+    realCurrPos= pos;
+  }
+
+public:
+  /**
+   * setRange
+   * Set the sub-range of the iterator.  Must be within the
+   * bounds of the underlying iterator
+   * After the range is set, the iterator is reset() to the
+   * start of the supplied subrange
+   */
+  bool setRange(Uint32 start, Uint32 len)
+  {
+    assert(checkInvariants());
+    if (start+len > realIterWords)
+      return false;
+    moveToPos(start);
+    
+    rangeStart= start;
+    rangeLen= rangeRemain= len;
+
+    assert(checkInvariants());
+    return true;
+  }
+
+  /**
+   * reset
+   * (GenericSectionIterator)
+   * Reset the iterator to the start of the current sub-range
+   * Avoid calling as it could be expensive.
+   */
+  void reset()
+  {
+    /* Reset iterator to last specified range */
+    assert(checkInvariants());
+    moveToPos(rangeStart);
+    rangeRemain= rangeLen;
+    assert(checkInvariants());
+  }
+
+  /**
+   * getNextWords
+   * (GenericSectionIterator)
+   * Get ptr and size of next contiguous words in subrange
+   */
+  Uint32* getNextWords(Uint32& sz)
+  {
+    assert(checkInvariants());
+    Uint32* currPtr= NULL;
+
+    if (rangeRemain)
+    {
+      assert(lastReadPtr != NULL);
+      assert(lastReadPtrLen != 0);
+      currPtr= lastReadPtr;
+      
+      sz= MIN(rangeRemain, lastReadPtrLen);
+      
+      if (sz == lastReadPtrLen)
+        /* Will return everything in this chunk, move iterator to 
+         * next
+         */
+        lastReadPtr= realIterator->getNextWords(lastReadPtrLen);
+      else
+      {
+        /* Not returning all of this chunk, just advance within it */
+        lastReadPtr+= sz;
+        lastReadPtrLen-= sz;
+      }
+      realCurrPos+= sz;
+      rangeRemain-= sz;
+    }
+    else
+    {
+      sz= 0;
+    }
+    
+    assert(checkInvariants());
+    return currPtr;
+  }
+};
+
+/* Max fragmented signal chunk size (words) is max round number 
+ * of NDB_SECTION_SEGMENT_SZ words with some slack left for 'main'
+ * part of signal etc.
+ */
+#define CHUNK_SZ ((((MAX_SEND_MESSAGE_BYTESIZE >> 2) / NDB_SECTION_SEGMENT_SZ) - 2 ) \
+                  * NDB_SECTION_SEGMENT_SZ)
+
+/**
+ * sendFragmentedSignal (GenericSectionPtr variant)
+ * ------------------------------------------------
+ * This method will send a signal with attached long sections.  If 
+ * the signal is longer than CHUNK_SZ, the signal will be split into
+ * multiple CHUNK_SZ fragments.
+ * 
+ * This is done by sending two or more long signals(fragments), with the
+ * original GSN, but different signal data and with as much of the long 
+ * sections as will fit in each.
+ *
+ * Non-final fragment signals contain a fraginfo value in the header
+ * (1= first fragment, 2= intermediate fragment, 3= final fragment)
+ * 
+ * Fragment signals contain additional words in their signals :
+ *   1..n words Mapping section numbers in fragment signal to original 
+ *              signal section numbers
+ *   1 word     Fragmented signal unique id.
+ * 
+ * Non final fragments (fraginfo=1/2) only have this data in them.  Final
+ * fragments have this data in addition to the normal signal data.
+ * 
+ * Each fragment signal can transport one or more long sections, starting 
+ * with section 0.  Sections are always split on NDB_SECTION_SEGMENT_SZ word
+ * boundaries to simplify reassembly in the kernel.
+ */
 int
 TransporterFacade::sendFragmentedSignal(NdbApiSignal* aSignal, NodeId aNode, 
-					LinearSectionPtr ptr[3], Uint32 secs)
+					GenericSectionPtr ptr[3], Uint32 secs)
 {
+  unsigned i;
+  Uint32 totalSectionLength= 0;
+  for (i= 0; i < secs; i++)
+    totalSectionLength+= ptr[i].sz;
+  
+  /* If there's no need to fragment, send normally */
+  if (totalSectionLength <= CHUNK_SZ)
+    return sendSignal(aSignal, aNode, ptr, secs);
+  
+  /* We will fragment */
   if(getIsNodeSendable(aNode) != true)
     return -1;
 
+  // TODO : Consider tracing fragment signals?
 #ifdef API_TRACE
   if(setSignalLog() && TRACE_GSN(aSignal->theVerId_signalNumber)){
     Uint32 tmp = aSignal->theSendersBlockRef;
@@ -1108,42 +1341,91 @@
 			    aNode,
 			    ptr, secs);
     aSignal->theSendersBlockRef = tmp;
+    /* Reset section iterators */
+    for(Uint32 s=0; s < secs; s++)
+      ptr[s].sectionIter->reset();
   }
 #endif
 
   NdbApiSignal tmp_signal(*(SignalHeader*)aSignal);
-  LinearSectionPtr tmp_ptr[3];
+  GenericSectionPtr tmp_ptr[3];
+  GenericSectionPtr empty= {0, NULL};
   Uint32 unique_id= m_fragmented_signal_id++; // next unique id
-  unsigned i;
-  for (i= 0; i < secs; i++)
-    tmp_ptr[i]= ptr[i];
+  
+  /* Init tmp_ptr array from ptr[] array, make sure we have
+   * 0 length for missing sections
+   */
+  for (i= 0; i < 3; i++)
+    tmp_ptr[i]= (i < secs)? ptr[i] : empty;
+
+  /* Create our section iterator adapters */
+  FragmentedSectionIterator sec0(tmp_ptr[0]);
+  FragmentedSectionIterator sec1(tmp_ptr[1]);
+  FragmentedSectionIterator sec2(tmp_ptr[2]);
+
+  /* Replace caller's iterators with ours */
+  tmp_ptr[0].sectionIter= &sec0;
+  tmp_ptr[1].sectionIter= &sec1;
+  tmp_ptr[2].sectionIter= &sec2;
 
   unsigned start_i= 0;
-  unsigned chunk_sz= 0;
+  unsigned this_chunk_sz= 0;
   unsigned fragment_info= 0;
-  Uint32 *tmp_data= tmp_signal.getDataPtrSend();
+  Uint32 *tmp_signal_data= tmp_signal.getDataPtrSend();
   for (i= 0; i < secs;) {
-    unsigned save_sz= tmp_ptr[i].sz;
-    tmp_data[i-start_i]= i;
-    if (chunk_sz + save_sz > CHUNK_SZ) {
-      // truncate
-      unsigned send_sz= CHUNK_SZ - chunk_sz;
-      if (i != start_i) // first piece of a new section has to be a multiple of NDB_SECTION_SEGMENT_SZ
+    unsigned remaining_sec_sz= tmp_ptr[i].sz;
+    tmp_signal_data[i-start_i]= i;
+    if (this_chunk_sz + remaining_sec_sz <= CHUNK_SZ)
+    {
+      /* This section fits whole, move onto next */
+      this_chunk_sz+= remaining_sec_sz;
+      i++;
+    }
+    else
+    {
+      /* This section doesn't fit, truncate it */
+      unsigned send_sz= CHUNK_SZ - this_chunk_sz;
+      if (i != start_i)
       {
+        /* We ensure that the first piece of a new section which is
+         * being truncated is a multiple of NDB_SECTION_SEGMENT_SZ
+         * (to simplify reassembly).  Subsequent non-truncated pieces
+         * will be CHUNK_SZ which is a multiple of NDB_SECTION_SEGMENT_SZ
+         * The final piece does not need to be a multiple of
+         * NDB_SECTION_SEGMENT_SZ
+         * 
+         * Note that this can push this_chunk_sz above CHUNK_SZ
+         * Should probably round-down, but need to be careful of
+         * 'can't fit any' cases.  Instead, CHUNK_SZ is defined
+         * with some slack below MAX_SENT_MESSAGE_BYTESIZE
+         */
 	send_sz=
 	  NDB_SECTION_SEGMENT_SZ
-	  *(send_sz+NDB_SECTION_SEGMENT_SZ-1)
-	  /NDB_SECTION_SEGMENT_SZ;
-	if (send_sz > save_sz)
-	  send_sz= save_sz;
+	  *((send_sz+NDB_SECTION_SEGMENT_SZ-1)
+            /NDB_SECTION_SEGMENT_SZ);
+        if (send_sz > remaining_sec_sz)
+	  send_sz= remaining_sec_sz;
       }
+
+      /* Modify tmp generic section ptr to describe truncated
+       * section
+       */
       tmp_ptr[i].sz= send_sz;
+      FragmentedSectionIterator* fragIter= 
+        (FragmentedSectionIterator*) tmp_ptr[i].sectionIter;
+      const Uint32 total_sec_sz= ptr[i].sz;
+      const Uint32 start= (total_sec_sz - remaining_sec_sz);
+      bool ok= fragIter->setRange(start, send_sz);
+      assert(ok);
+      if (!ok)
+        return -1;
       
-      if (fragment_info < 2) // 1 = first fragment, 2 = middle fragments
+      if (fragment_info < 2) // 1 = first fragment signal
+                             // 2 = middle fragments
 	fragment_info++;
 
       // send tmp_signal
-      tmp_data[i-start_i+1]= unique_id;
+      tmp_signal_data[i-start_i+1]= unique_id;
       tmp_signal.setLength(i-start_i+2);
       tmp_signal.m_fragmentInfo= fragment_info;
       tmp_signal.m_noOfSections= i-start_i+1;
@@ -1152,7 +1434,7 @@
 	SendStatus ss = theTransporterRegistry->prepareSend
 	  (&tmp_signal, 
 	   1, /*JBB*/
-	   tmp_data,
+	   tmp_signal_data,
 	   aNode, 
 	   &tmp_ptr[start_i]);
 	assert(ss != SEND_MESSAGE_TOO_BIG);
@@ -1160,17 +1442,20 @@
       }
       // setup variables for next signal
       start_i= i;
-      chunk_sz= 0;
-      tmp_ptr[i].sz= save_sz-send_sz;
-      tmp_ptr[i].p+= send_sz;
-      if (tmp_ptr[i].sz == 0)
+      this_chunk_sz= 0;
+      assert(remaining_sec_sz >= send_sz);
+      Uint32 remaining= remaining_sec_sz - send_sz;
+      tmp_ptr[i].sz= remaining;
+      /* Set sub-range iterator to cover remaining words */
+      ok= fragIter->setRange(start+send_sz, remaining);
+      assert(ok);
+      if (!ok)
+        return -1;
+      
+      if (remaining == 0)
+        /* This section's done, move onto the next */
 	i++;
     }
-    else
-    {
-      chunk_sz+=save_sz;
-      i++;
-    }
   }
 
   unsigned a_sz= aSignal->getLength();
@@ -1180,7 +1465,7 @@
     Uint32 *a_data= aSignal->getDataPtrSend();
     unsigned tmp_sz= i-start_i;
     memcpy(a_data+a_sz,
-	   tmp_data,
+	   tmp_signal_data,
 	   tmp_sz*sizeof(Uint32));
     a_data[a_sz+tmp_sz]= unique_id;
     aSignal->setLength(a_sz+tmp_sz+1);
@@ -1211,6 +1496,26 @@
 }
 
 int
+TransporterFacade::sendFragmentedSignal(NdbApiSignal* aSignal, NodeId aNode, 
+					LinearSectionPtr ptr[3], Uint32 secs)
+{
+  /* Use the GenericSection variant of sendFragmentedSignal */
+  GenericSectionPtr tmpPtr[3];
+  LinearSectionIterator zero (ptr[0].p, ptr[0].sz);
+  LinearSectionIterator one  (ptr[1].p, ptr[1].sz);
+  LinearSectionIterator two  (ptr[2].p, ptr[2].sz);
+  tmpPtr[0].sz= ptr[0].sz;
+  tmpPtr[0].sectionIter= &zero;
+  tmpPtr[1].sz= ptr[1].sz;
+  tmpPtr[1].sectionIter= &one;
+  tmpPtr[2].sz= ptr[2].sz;
+  tmpPtr[2].sectionIter= &two;
+
+  return sendFragmentedSignal(aSignal, aNode, tmpPtr, secs);
+}
+  
+
+int
 TransporterFacade::sendSignal(NdbApiSignal* aSignal, NodeId aNode, 
 			      LinearSectionPtr ptr[3], Uint32 secs){
   aSignal->m_noOfSections = secs;
@@ -1259,6 +1564,9 @@
       signalLogger.flushSignalLog();
       aSignal->theSendersBlockRef = tmp;
     }
+    /* Reset section iterators */
+    for(Uint32 s=0; s < secs; s++)
+      ptr[s].sectionIter->reset();
 #endif
     SendStatus ss = theTransporterRegistry->prepareSend
       (aSignal, 
@@ -1650,3 +1958,274 @@
 
   return ss;
 }
+
+
+Uint32*
+SignalSectionIterator::getNextWords(Uint32& sz)
+{
+  if (likely(currentSignal != NULL))
+  {
+    NdbApiSignal* signal= currentSignal;
+    currentSignal= currentSignal->next();
+    sz= signal->getLength();
+    return signal->getDataPtrSend();
+  }
+  sz= 0;
+  return NULL;
+}
+
+
+// Unit test code starts
+#include <random.h>
+
+#define VERIFY(x) if ((x) == 0) { printf("VERIFY failed at Line %u : %s\n",__LINE__, #x);  return -1; }
+
+/* Verify that word[n] == bias + n */
+int
+verifyIteratorContents(GenericSectionIterator& gsi, int dataWords, int bias)
+{
+  int pos= 0;
+
+  while (pos < dataWords)
+  {
+    Uint32* readPtr=NULL;
+    Uint32 len= 0;
+
+    readPtr= gsi.getNextWords(len);
+    
+    VERIFY(readPtr != NULL);
+    VERIFY(len != 0);
+    VERIFY(len <= (Uint32) (dataWords - pos));
+    
+    for (int j=0; j < (int) len; j++)
+      VERIFY(readPtr[j] == (Uint32) (bias ++));
+
+    pos += len;
+  }
+
+  return 0;
+}
+
+int
+checkGenericSectionIterator(GenericSectionIterator& iter, int size, int bias)
+{
+  /* Verify contents */
+  VERIFY(verifyIteratorContents(iter, size, bias) == 0);
+  
+  Uint32 sz;
+  
+  /* Check that iterator is empty now */
+  VERIFY(iter.getNextWords(sz) == NULL);
+  VERIFY(sz == 0);
+    
+  VERIFY(iter.getNextWords(sz) == NULL);
+  VERIFY(sz == 0);
+  
+  iter.reset();
+  
+  /* Verify reset put us back to the start */
+  VERIFY(verifyIteratorContents(iter, size, bias) == 0);
+  
+  /* Verify no more words available */
+  VERIFY(iter.getNextWords(sz) == NULL);
+  VERIFY(sz == 0);  
+  
+  return 0;
+}
+
+int
+checkIterator(GenericSectionIterator& iter, int size, int bias)
+{
+  /* Test iterator itself, and then FragmentedSectionIterator
+   * adaptation
+   */
+  VERIFY(checkGenericSectionIterator(iter, size, bias) == 0);
+  
+  /* Now we'll test the FragmentedSectionIterator on the iterator
+   * we were passed
+   */
+  const int subranges= 20;
+  
+  iter.reset();
+  GenericSectionPtr ptr;
+  ptr.sz= size;
+  ptr.sectionIter= &iter;
+  FragmentedSectionIterator fsi(ptr);
+
+  for (int s=0; s< subranges; s++)
+  {
+    Uint32 start= 0;
+    Uint32 len= 0;
+    if (size > 0)
+    {
+      start= (Uint32) myRandom48(size);
+      if (0 != (size-start)) 
+        len= (Uint32) myRandom48(size-start);
+    }
+    
+    /*
+      printf("Range (0-%u) = (%u + %u)\n",
+              size, start, len);
+    */
+    fsi.setRange(start, len);
+    VERIFY(checkGenericSectionIterator(fsi, len, bias + start) == 0);
+  }
+  
+  return 0;
+}
+
+
+
+int
+testLinearSectionIterator()
+{
+  /* Test Linear section iterator of various
+   * lengths with section[n] == bias + n
+   */
+  const int totalSize= 200000;
+  const int bias= 13;
+
+  Uint32 data[totalSize];
+  for (int i=0; i<totalSize; i++)
+    data[i]= bias + i;
+
+  for (int len= 0; len < 50000; len++)
+  {
+    LinearSectionIterator something(data, len);
+
+    VERIFY(checkIterator(something, len, bias) == 0);
+  }
+
+  return 0;
+}
+
+NdbApiSignal*
+createSignalChain(NdbApiSignal*& poolHead, int length, int bias)
+{
+  /* Create signal chain, with word[n] == bias+n */
+  NdbApiSignal* chainHead= NULL;
+  NdbApiSignal* chainTail= NULL;
+  int pos= 0;
+  int signals= 0;
+
+  while (pos < length)
+  {
+    int offset= pos % NdbApiSignal::MaxSignalWords;
+    
+    if (offset == 0)
+    {
+      if (poolHead == NULL)
+        return 0;
+
+      NdbApiSignal* newSig= poolHead;
+      poolHead= poolHead->next();
+      signals++;
+
+      newSig->next(NULL);
+
+      if (chainHead == NULL)
+      {
+        chainHead= chainTail= newSig;
+      }
+      else
+      {
+        chainTail->next(newSig);
+        chainTail= newSig;
+      }
+    }
+    
+    chainTail->getDataPtrSend()[offset]= (bias + pos);
+    chainTail->setLength(offset + 1);
+    pos ++;
+  }
+
+  return chainHead;
+}
+    
+int
+testSignalSectionIterator()
+{
+  /* Create a pool of signals, build
+   * signal chains from it, test
+   * the iterator against the signal chains
+   */
+  const int totalNumSignals= 1000;
+  NdbApiSignal* poolHead= NULL;
+
+  /* Allocate some signals */
+  for (int i=0; i < totalNumSignals; i++)
+  {
+    NdbApiSignal* sig= new NdbApiSignal((BlockReference) 0);
+
+    if (poolHead == NULL)
+    {
+      poolHead= sig;
+      sig->next(NULL);
+    }
+    else
+    {
+      sig->next(poolHead);
+      poolHead= sig;
+    }
+  }
+
+  const int bias= 7;
+  for (int dataWords= 1; 
+       dataWords <= (int)(totalNumSignals * 
+                          NdbApiSignal::MaxSignalWords); 
+       dataWords ++)
+  {
+    NdbApiSignal* signalChain= NULL;
+    
+    VERIFY((signalChain= createSignalChain(poolHead, dataWords, bias)) != NULL );
+    
+    SignalSectionIterator ssi(signalChain);
+    
+    VERIFY(checkIterator(ssi, dataWords, bias) == 0);
+    
+    /* Now return the signals to the pool */
+    while (signalChain != NULL)
+    {
+      NdbApiSignal* sig= signalChain;
+      signalChain= signalChain->next();
+      
+      sig->next(poolHead);
+      poolHead= sig;
+    }
+  }
+  
+  /* Free signals from pool */
+  while (poolHead != NULL)
+  {
+    NdbApiSignal* sig= poolHead;
+    poolHead= sig->next();
+    delete(sig);
+  }
+  
+  return 0;
+}
+
+//#define WANT_TESTSECTIONITERATORS 1
+
+#ifdef WANT_TESTSECTIONITERATORS
+int main(int arg, char** argv)
+{
+  /* Test Section Iterators
+   * ----------------------
+   * To run this code : 
+   *   cd storage/ndb/src/ndbapi
+   *   make testSectionIterators
+   *   ./testSectionIterators
+   *
+   * Will print "OK" in success case
+   */
+  
+
+  VERIFY(testLinearSectionIterator() == 0);
+  VERIFY(testSignalSectionIterator() == 0);
+  
+  printf("OK\n");
+
+  return 0;
+}
+#endif

=== modified file 'storage/ndb/src/ndbapi/TransporterFacade.hpp'
--- a/storage/ndb/src/ndbapi/TransporterFacade.hpp	2008-07-22 13:42:54 +0000
+++ b/storage/ndb/src/ndbapi/TransporterFacade.hpp	2008-08-26 14:05:01 +0000
@@ -78,6 +78,8 @@
                  GenericSectionPtr ptr[3], Uint32 secs);
   int sendFragmentedSignal(NdbApiSignal*, NodeId, 
 			   LinearSectionPtr ptr[3], Uint32 secs);
+  int sendFragmentedSignal(NdbApiSignal*, NodeId,
+                           GenericSectionPtr ptr[3], Uint32 secs);
 
   // Is node available for running transactions
   bool   get_node_alive(NodeId nodeId) const;
@@ -441,6 +443,83 @@
   return m_batch_size;
 }
 
-
+/** 
+ * LinearSectionIterator
+ *
+ * This is an implementation of GenericSectionIterator 
+ * that iterates over one linear section of memory.
+ * The iterator is used by the transporter at signal
+ * send time to obtain all of the relevant words for the
+ * signal section
+ */
+class LinearSectionIterator: public GenericSectionIterator
+{
+private :
+  Uint32* data;
+  Uint32 len;
+  bool read;
+public :
+  LinearSectionIterator(Uint32* _data, Uint32 _len)
+  {
+    data= (_len == 0)? NULL:_data;
+    len= _len;
+    read= false;
+  }
+
+  ~LinearSectionIterator()
+  {};
+  
+  void reset()
+  {
+    /* Reset iterator */
+    read= false;
+  }
+
+  Uint32* getNextWords(Uint32& sz)
+  {
+    if (likely(!read))
+    {
+      read= true;
+      sz= len;
+      return data;
+    }
+    sz= 0;
+    return NULL;
+  }
+};
+
+
+/** 
+ * SignalSectionIterator
+ *
+ * This is an implementation of GenericSectionIterator 
+ * that uses chained NdbApiSignal objects to store a 
+ * signal section.
+ * The iterator is used by the transporter at signal
+ * send time to obtain all of the relevant words for the
+ * signal section
+ */
+class SignalSectionIterator: public GenericSectionIterator
+{
+private :
+  NdbApiSignal* firstSignal;
+  NdbApiSignal* currentSignal;
+public :
+  SignalSectionIterator(NdbApiSignal* signal)
+  {
+    firstSignal= currentSignal= signal;
+  }
+
+  ~SignalSectionIterator()
+  {};
+  
+  void reset()
+  {
+    /* Reset iterator */
+    currentSignal= firstSignal;
+  }
+
+  Uint32* getNextWords(Uint32& sz);
+};
 
 #endif // TransporterFacade_H

=== modified file 'storage/ndb/test/ndbapi/testLimits.cpp'
--- a/storage/ndb/test/ndbapi/testLimits.cpp	2008-08-04 13:40:17 +0000
+++ b/storage/ndb/test/ndbapi/testLimits.cpp	2008-08-26 14:05:01 +0000
@@ -808,6 +808,117 @@
 }
 
 
+int testSegmentedSectionScan(NDBT_Context* ctx, NDBT_Step* step){
+  /* Test that TC handling of segmented section exhaustion is
+   * correct
+   * Since NDBAPI always send long requests, that is all that
+   * we test
+   */
+    /* 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);
+  char smallKey[50];
+  char smallRowBuf[maxRowBytes];
+
+  Uint32 smallKeySize= setLongVarchar(&smallKey[0],
+                                      "ShortKey",
+                                      8);
+
+  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);
+
+  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
+   * A scan will always send 2 long sections (Receiver Ids
+   * + AttrInfo), so let's start a scan with > 2400 bytes of
+   * ATTRINFO and see what happens
+   */
+  NdbScanOperation* scan= trans->getNdbScanOperation(ctx->getTab());
+
+  CHECKNOTNULL(scan);
+
+  CHECKEQUAL(0, scan->readTuples());
+
+  /* Create a particularly useless program */
+  NdbInterpretedCode prog;
+
+  for (Uint32 w=0; w < 2500; w++)
+    CHECKEQUAL(0, prog.load_const_null(1));
+
+  CHECKEQUAL(0, prog.interpret_exit_ok());
+  CHECKEQUAL(0, prog.finalise());
+
+  CHECKEQUAL(0, scan->setInterpretedCode(&prog));
+
+  /* Api doesn't seem to wait for result of scan request */
+  CHECKEQUAL(0, trans->execute(NdbTransaction::NoCommit));
+
+  CHECKEQUAL(0, trans->getNdbError().code);
+
+  CHECKEQUAL(-1, scan->nextResult());
+  
+  CHECKEQUAL(217, scan->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, 
+                                          record, 
+                                          ctx->getTab(),
+                                          smallRowBuf, 
+                                          &restarter, 
+                                          8068));
+
+  CHECKEQUAL(0, trans->execute(NdbTransaction::Rollback));
+  
+  CHECKEQUAL(0, trans->getNdbError().code);
+
+  trans->close();
+
+  return NDBT_OK;
+}
+
 NDBT_TESTSUITE(testLimits);
 
 TESTCASE("ExhaustSegmentedSectionPk",
@@ -816,9 +927,13 @@
 }
 
 TESTCASE("ExhaustSegmentedSectionIX",
-         "Test behaviour at Segmented Section exhaustion for PK"){
+         "Test behaviour at Segmented Section exhaustion for Unique index"){
   INITIALIZER(testSegmentedSectionIx);
 }
+TESTCASE("ExhaustSegmentedSectionScan",
+         "Test behaviour at Segmented Section exhaustion for Scan"){
+  INITIALIZER(testSegmentedSectionScan);
+}
 
 NDBT_TESTSUITE_END(testLimits);
 

=== 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:30:18 +0000
+++ b/storage/ndb/test/run-test/daily-basic-tests.txt	2008-08-26 14:05:01 +0000
@@ -1216,3 +1216,10 @@
 args -r 5000 -n Bug30780 T1
 
 #EOF 2008-08-11
+
+# Test data buffering for SCANTABREQ
+max-time: 500
+cmd: testLimits
+args: -n ExhaustSegmentedSectionScan WIDE_2COL
+
+#EOF 2008-08-20



