List:Commits« Previous MessageNext Message »
From:knielsen Date:May 8 2007 12:28pm
Subject:bk commit into 5.1 tree (knielsen:1.2506)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of knielsen. When knielsen does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2007-05-08 12:28:47+02:00, knielsen@ymer.(none) +8 -0
  Merge ymer.(none):/usr/local/mysql/mysql-5.1-ndb-ndbrecord
  into  ymer.(none):/usr/local/mysql/mysql-5.1-telco-ndbrecord
  MERGE: 1.2502.1.5

  storage/ndb/include/ndbapi/NdbOperation.hpp@stripped, 2007-05-08 12:28:41+02:00,
knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.48.1.1

  storage/ndb/include/ndbapi/NdbRecAttr.hpp@stripped, 2007-05-08 12:28:41+02:00,
knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.23.1.1

  storage/ndb/include/ndbapi/NdbReceiver.hpp@stripped, 2007-05-08 12:28:41+02:00,
knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.26.1.1

  storage/ndb/src/ndbapi/NdbOperationDefine.cpp@stripped, 2007-05-08 12:28:41+02:00,
knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.32.1.1

  storage/ndb/src/ndbapi/NdbOperationExec.cpp@stripped, 2007-05-08 12:28:41+02:00,
knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.34.1.1

  storage/ndb/src/ndbapi/NdbReceiver.cpp@stripped, 2007-05-08 12:28:41+02:00,
knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.28.1.1

  storage/ndb/src/ndbapi/NdbScanOperation.cpp@stripped, 2007-05-08 12:28:41+02:00,
knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.114.1.1

  storage/ndb/src/ndbapi/NdbTransaction.cpp@stripped, 2007-05-08 12:28:41+02:00,
knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.81.1.1

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	knielsen
# Host:	ymer.(none)
# Root:	/usr/local/mysql/mysql-5.1-telco-ndbrecord/RESYNC

--- 1.49/storage/ndb/include/ndbapi/NdbOperation.hpp	2007-05-08 12:28:55 +02:00
+++ 1.50/storage/ndb/include/ndbapi/NdbOperation.hpp	2007-05-08 12:28:55 +02:00
@@ -1010,6 +1010,7 @@ protected:
 
   virtual int equal_impl(const NdbColumnImpl*,const char* aValue);
   virtual NdbRecAttr* getValue_impl(const NdbColumnImpl*, char* aValue = 0);
+  NdbRecAttr* getValue_NdbRecord(const NdbColumnImpl* tAttrInfo, char* aValue);
   int setValue(const NdbColumnImpl* anAttrObject, const char* aValue);
   NdbBlob* getBlobHandle(NdbTransaction* aCon, const NdbColumnImpl* anAttrObject);
   int incValue(const NdbColumnImpl* anAttrObject, Uint32 aValue);
@@ -1270,7 +1271,7 @@ inline
 const NdbRecAttr*
 NdbOperation::getFirstRecAttr() const 
 {
-  return theReceiver.m_recattr.theFirstRecAttr;
+  return theReceiver.theFirstRecAttr;
 }
 
 /******************************************************************************

--- 1.24/storage/ndb/include/ndbapi/NdbRecAttr.hpp	2007-05-08 12:28:55 +02:00
+++ 1.25/storage/ndb/include/ndbapi/NdbRecAttr.hpp	2007-05-08 12:28:55 +02:00
@@ -73,6 +73,7 @@ class NdbRecAttr
 {
 #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
   friend class NdbOperation;
+  friend class NdbScanOperation;
   friend class NdbIndexScanOperation;
   friend class NdbEventOperationImpl;
   friend class NdbReceiver;

--- 1.27/storage/ndb/include/ndbapi/NdbReceiver.hpp	2007-05-08 12:28:55 +02:00
+++ 1.28/storage/ndb/include/ndbapi/NdbReceiver.hpp	2007-05-08 12:28:55 +02:00
@@ -86,9 +86,9 @@ private:
   */
   void do_setup_ndbrecord(const NdbRecord *ndb_record, Uint32 batch_size,
                           Uint32 key_size, Uint32 read_range_no,
-                          Uint32 rowsize, char *buf);
+                          Uint32 rowsize, char *buf, Uint32 column_count);
   Uint32 ndbrecord_rowsize(const NdbRecord *ndb_record, Uint32 key_size,
-                           Uint32 read_range_no, Uint32 blobs_size);
+                           Uint32 read_range_no, Uint32 extra_size);
 
   void receiveBlobHead(const NdbRecord *record, Uint32 record_pos,
                        const Uint32 *src, Uint32 byteSize,
@@ -99,20 +99,19 @@ private:
   int execSCANOPCONF(Uint32 tcPtrI, Uint32 len, Uint32 rows);
 
   /*
-    We need to keep different state for old NdbRecAttr based operation and for
+    We keep different state for old NdbRecAttr based operation and for
     new NdbRecord style operation.
   */
   bool m_using_ndb_record;
   union {
     /* members used for NdbRecAttr operation. */
     struct {
-      class NdbRecAttr* theFirstRecAttr;
-      class NdbRecAttr* theCurrentRecAttr;
       Uint32 m_hidden_count;
     } m_recattr;
 
     /* members used for NdbRecord operation. */
     struct {
+      Uint32 m_column_count;
       const NdbRecord *m_ndb_record;
       char *m_row;
       /* Block of memory used to receive all rows in a batch during scan. */
@@ -131,6 +130,9 @@ private:
       bool m_read_range_no;
     } m_record;
   };
+  class NdbRecAttr* theFirstRecAttr;
+  class NdbRecAttr* theCurrentRecAttr;
+
   /*
     m_rows is only used in NdbRecAttr mode, but is kept during NdbRecord mode
     operation to avoid the need for re-allocation.
@@ -192,7 +194,7 @@ private:
   /* get_keyinfo20)_ returns keyinfo from KEYINFO20 signal. */
   int get_keyinfo20(Uint32 & scaninfo, Uint32 & length,
                     const char * & data_ptr) const;
-  int getBlobHead(const char * & data, Uint32 & size, Uint32 & pos) const;
+  int getScanAttrData(const char * & data, Uint32 & size, Uint32 & pos)
const;
 };
 
 #ifdef NDB_NO_DROPPED_SIGNAL
@@ -223,10 +225,7 @@ NdbReceiver::prepareSend(){
     if (m_type==NDB_SCANRECEIVER)
       m_record.m_row= m_record.m_row_buffer;
   }
-  else
-  {
-    m_recattr.theCurrentRecAttr = m_recattr.theFirstRecAttr;
-  }
+  theCurrentRecAttr = theFirstRecAttr;
 }
 
 inline

--- 1.82/storage/ndb/src/ndbapi/NdbTransaction.cpp	2007-05-08 12:28:55 +02:00
+++ 1.83/storage/ndb/src/ndbapi/NdbTransaction.cpp	2007-05-08 12:28:55 +02:00
@@ -2312,6 +2312,7 @@ NdbTransaction::scanTable(const NdbRecor
   NdbIndexScanOperation *op_idx;
   NdbScanOperation *op;
   NdbBlob *lastBlob;
+  Uint32 column_count;
   int res;
 
   op_idx= getNdbScanOperation(result_record->table);
@@ -2329,6 +2330,7 @@ NdbTransaction::scanTable(const NdbRecor
   result_record->copyMask(op->m_read_mask, result_mask);
 
   lastBlob= NULL;
+  column_count= 0;
   for (Uint32 i= 0; i<result_record->noOfColumns; i++)
   {
     const NdbRecord::Attr *col;
@@ -2361,7 +2363,9 @@ NdbTransaction::scanTable(const NdbRecor
 
     if (col->flags & NdbRecord::IsDisk)
       op->m_no_disk_flag= false;
+    column_count++;
   }
+  op->theReceiver.m_record.m_column_count= column_count;
 
   /*
     We set theStatus=UseNdbRecord to allow the addition of an interpreted

--- 1.33/storage/ndb/src/ndbapi/NdbOperationDefine.cpp	2007-05-08 12:28:55 +02:00
+++ 1.34/storage/ndb/src/ndbapi/NdbOperationDefine.cpp	2007-05-08 12:28:55 +02:00
@@ -382,6 +382,8 @@ NdbOperation::getValue_impl(const NdbCol
       (theStatus != Init)){
     m_no_disk_flag &= (tAttrInfo->m_storageType == NDB_STORAGETYPE_DISK ? 0:1);
     if (theStatus != GetValue) {
+      if (theStatus == UseNdbRecord)
+        return getValue_NdbRecord(tAttrInfo, aValue);
       if (theInterpretIndicator == 1) {
 	if (theStatus == FinalGetValue) {
 	  ; // Simply continue with getValue
@@ -430,6 +432,23 @@ NdbOperation::getValue_impl(const NdbCol
   }//if
   setErrorCodeAbort(4200);
   return NULL;
+}
+
+NdbRecAttr*
+NdbOperation::getValue_NdbRecord(const NdbColumnImpl* tAttrInfo, char* aValue)
+{
+  NdbRecAttr* tRecAttr;
+  /*
+    For getValue with NdbRecord operations, we just allocate the NdbRecAttr,
+    the signal data will be constructed later.
+  */
+  if((tRecAttr = theReceiver.getValue(tAttrInfo, aValue)) != 0) {
+    theErrorLine++;
+    return tRecAttr;
+  } else {
+    setErrorCodeAbort(4000);
+    return NULL;
+  }
 }
 
 /*****************************************************************************

--- 1.35/storage/ndb/src/ndbapi/NdbOperationExec.cpp	2007-05-08 12:28:55 +02:00
+++ 1.36/storage/ndb/src/ndbapi/NdbOperationExec.cpp	2007-05-08 12:28:55 +02:00
@@ -793,6 +793,7 @@ NdbOperation::prepareSendNdbRecord(Uint3
   }
   else if (tOpType == ReadRequest || tOpType == ReadExclusive)
   {
+    Uint32 column_count= 0;
     for (Uint32 i= 0; i<attr_rec->noOfColumns; i++)
     {
       const NdbRecord::Attr *col;
@@ -818,6 +819,20 @@ NdbOperation::prepareSendNdbRecord(Uint3
                                        &attrInfoPtr, &remain);
       if(res)
         return res;
+      column_count++;
+    }
+    theReceiver.m_record.m_column_count= column_count;
+
+    /* Handle any additional getValue(). */
+    const NdbRecAttr *ra= theReceiver.theFirstRecAttr;
+    while (ra)
+    {
+      res= insertATTRINFOHdr_NdbRecord(aTC_ConnectPtr, aTransId,
+                                       ra->attrId(), 0,
+                                       &attrInfoPtr, &remain);
+      if(res)
+        return res;
+      ra= ra->next();
     }
   }
   Uint32 signalLength= hdrSize +

--- 1.29/storage/ndb/src/ndbapi/NdbReceiver.cpp	2007-05-08 12:28:55 +02:00
+++ 1.30/storage/ndb/src/ndbapi/NdbReceiver.cpp	2007-05-08 12:28:55 +02:00
@@ -33,7 +33,7 @@ NdbReceiver::NdbReceiver(Ndb *aNdb) :
   m_owner(0),
   m_using_ndb_record(false)
 {
-  m_recattr.theCurrentRecAttr = m_recattr.theFirstRecAttr = 0;
+  theCurrentRecAttr = theFirstRecAttr = 0;
   m_defined_rows = 0;
   m_rows = NULL;
 }
@@ -63,12 +63,10 @@ NdbReceiver::init(ReceiverType type, boo
     m_record.m_row_buffer= NULL;
     m_record.m_row_offset= 0;
     m_record.m_read_range_no= false;
+    m_record.m_column_count= 0;
   }
-  else
-  {
-    m_recattr.theFirstRecAttr = NULL;
-    m_recattr.theCurrentRecAttr = NULL;
-  }
+  theFirstRecAttr = NULL;
+  theCurrentRecAttr = NULL;
 
   if (m_id == NdbObjectIdMap::InvalidId) {
     if (m_ndb)
@@ -87,32 +85,27 @@ NdbReceiver::init(ReceiverType type, boo
 
 void
 NdbReceiver::release(){
-  if (!m_using_ndb_record)
+  NdbRecAttr* tRecAttr = theFirstRecAttr;
+  while (tRecAttr != NULL)
   {
-    NdbRecAttr* tRecAttr = m_recattr.theFirstRecAttr;
-    while (tRecAttr != NULL)
-    {
-      NdbRecAttr* tSaveRecAttr = tRecAttr;
-      tRecAttr = tRecAttr->next();
-      m_ndb->releaseRecAttr(tSaveRecAttr);
-    }
+    NdbRecAttr* tSaveRecAttr = tRecAttr;
+    tRecAttr = tRecAttr->next();
+    m_ndb->releaseRecAttr(tSaveRecAttr);
   }
   m_using_ndb_record= false;
-  m_recattr.theFirstRecAttr = NULL;
-  m_recattr.theCurrentRecAttr = NULL;
+  theFirstRecAttr = NULL;
+  theCurrentRecAttr = NULL;
 }
   
 NdbRecAttr *
 NdbReceiver::getValue(const NdbColumnImpl* tAttrInfo, char * user_dst_ptr){
-  assert(!m_using_ndb_record);
-
   NdbRecAttr* tRecAttr = m_ndb->getRecAttr();
   if(tRecAttr && !tRecAttr->setup(tAttrInfo, user_dst_ptr)){
-    if (m_recattr.theFirstRecAttr == NULL)
-      m_recattr.theFirstRecAttr = tRecAttr;
+    if (theFirstRecAttr == NULL)
+      theFirstRecAttr = tRecAttr;
     else
-      m_recattr.theCurrentRecAttr->next(tRecAttr);
-    m_recattr.theCurrentRecAttr = tRecAttr;
+      theCurrentRecAttr->next(tRecAttr);
+    theCurrentRecAttr = tRecAttr;
     tRecAttr->next(NULL);
     return tRecAttr;
   }
@@ -158,16 +151,15 @@ NdbReceiver::calculate_batch_size(Uint32
   {
     tot_size+= record->m_max_transid_ai_bytes;
   }
-  else
-  {
-    NdbRecAttr *rec_attr= m_recattr.theFirstRecAttr;
-    while (rec_attr != NULL) {
-      Uint32 attr_size= rec_attr->getColumn()->getSizeInBytes();
-      attr_size= ((attr_size + 7) >> 2) << 2; //Even to word + overhead
-      tot_size+= attr_size;
-      rec_attr= rec_attr->next();
-    }
+
+  NdbRecAttr *rec_attr= theFirstRecAttr;
+  while (rec_attr != NULL) {
+    Uint32 attr_size= rec_attr->getColumn()->getSizeInBytes();
+    attr_size= ((attr_size + 7) >> 2) << 2; //Even to word + overhead
+    tot_size+= attr_size;
+    rec_attr= rec_attr->next();
   }
+
   tot_size+= 32; //include signal overhead
 
   /**
@@ -236,7 +228,7 @@ NdbReceiver::do_get_value(NdbReceiver * 
   m_recattr.m_hidden_count = (key_size ? 1 : 0) + range_no ;
   
   for(Uint32 i = 0; i<batch_size; i++){
-    NdbRecAttr * prev = m_recattr.theCurrentRecAttr;
+    NdbRecAttr * prev = theCurrentRecAttr;
     assert(prev == 0 || i > 0);
     
     // Put key-recAttr fir on each row
@@ -251,7 +243,7 @@ NdbReceiver::do_get_value(NdbReceiver * 
       abort();
     }
 
-    NdbRecAttr* tRecAttr = org->m_recattr.theFirstRecAttr;
+    NdbRecAttr* tRecAttr = org->theFirstRecAttr;
     while(tRecAttr != 0){
       if(getValue(&NdbColumnImpl::getImpl(*tRecAttr->m_column), (char*)0) != 0)
 	tRecAttr = tRecAttr->next();
@@ -268,7 +260,7 @@ NdbReceiver::do_get_value(NdbReceiver * 
     if(prev){
       m_rows[i] = prev->next();
     } else {
-      m_rows[i] = m_recattr.theFirstRecAttr;
+      m_rows[i] = theFirstRecAttr;
     }
   } 
 
@@ -279,7 +271,8 @@ NdbReceiver::do_get_value(NdbReceiver * 
 void
 NdbReceiver::do_setup_ndbrecord(const NdbRecord *ndb_record, Uint32 batch_size,
                                 Uint32 key_size, Uint32 read_range_no,
-                                Uint32 rowsize, char *row_buffer)
+                                Uint32 rowsize, char *row_buffer,
+                                Uint32 column_count)
 {
   m_using_ndb_record= true;
   m_record.m_ndb_record= ndb_record;
@@ -287,11 +280,12 @@ NdbReceiver::do_setup_ndbrecord(const Nd
   m_record.m_row_buffer= row_buffer;
   m_record.m_row_offset= rowsize;
   m_record.m_read_range_no= read_range_no;
+  m_record.m_column_count= column_count;
 }
 
 Uint32
 NdbReceiver::ndbrecord_rowsize(const NdbRecord *ndb_record, Uint32 key_size,
-                               Uint32 read_range_no, Uint32 blobs_size)
+                               Uint32 read_range_no, Uint32 extra_size)
 {
   Uint32 rowsize= ndb_record->m_row_size;
   /* Room for range_no. */
@@ -304,7 +298,7 @@ NdbReceiver::ndbrecord_rowsize(const Ndb
   if (key_size)
     rowsize+= 8 + key_size*4;
   /* Space for reading blob heads. */
-  rowsize+= blobs_size;
+  rowsize+= extra_size;
   /* Ensure 4-byte alignment. */
   rowsize= (rowsize+3) & 0xfffffffc;
   return rowsize;
@@ -314,7 +308,7 @@ NdbRecAttr*
 NdbReceiver::copyout(NdbReceiver & dstRec){
   assert(!m_using_ndb_record);
   NdbRecAttr *src = m_rows[m_current_row++];
-  NdbRecAttr *dst = dstRec.m_recattr.theFirstRecAttr;
+  NdbRecAttr *dst = dstRec.theFirstRecAttr;
   NdbRecAttr *start = src;
   Uint32 tmp = m_recattr.m_hidden_count;
   while(tmp--)
@@ -528,7 +522,7 @@ NdbReceiver::receiveBlobHead(const NdbRe
 }
 
 int
-NdbReceiver::getBlobHead(const char * & data, Uint32 & size, Uint32 & pos)
const
+NdbReceiver::getScanAttrData(const char * & data, Uint32 & size, Uint32 &
pos) const
 {
   assert(m_using_ndb_record);
   Uint32 idx= m_current_row;
@@ -553,7 +547,8 @@ NdbReceiver::execTRANSID_AI(const Uint32
     Uint32 tmp= m_received_result_length + aLength;
     const NdbRecord *rec= m_record.m_ndb_record;
     Uint32 rec_pos= 0;
-    Uint32 blob_pos= 0;
+    Uint32 save_pos= 0;
+    Uint32 column_count= 0;
 
     while (aLength > 0)
     {
@@ -581,11 +576,46 @@ NdbReceiver::execTRANSID_AI(const Uint32
              rec->columns[rec_pos].attrId < attrId)
         rec_pos++;
 
+      /*
+        To support extra getValue(), there may be extra attribute data after
+        all NdbRecord columns have been fetched. But the fast path is for pure
+        NdbRecord operation, with no extra getValue().
+      */
+      if (unlikely(column_count >= m_record.m_column_count))
+      {
+        if (m_type == NDB_SCANRECEIVER)
+        {
+          /* For scans, save the data and copy to NdbRecAttr in nextResult(). */
+          save_pos+= sizeof(Uint32);
+          memcpy(m_record.m_row + m_record.m_row_offset - save_pos,
+                 &attrSize, sizeof(Uint32));
+          if (attrSize > 0)
+          {
+            save_pos+= attrSize;
+            memcpy(m_record.m_row + m_record.m_row_offset - save_pos,
+                   aDataPtr, attrSize);
+          }
+        }
+        else
+        {
+          /* Handle extra attributes requested with getValue(). */
+          assert(theCurrentRecAttr != NULL);
+          assert(theCurrentRecAttr->attrId() == attrId);
+          bool res= theCurrentRecAttr->receive_data(aDataPtr, attrSize);
+          assert(res);
+          theCurrentRecAttr= theCurrentRecAttr->next();
+        }
+        Uint32 sizeInWords= (attrSize+3)>>2;
+        aDataPtr+= sizeInWords;
+        aLength-= sizeInWords;
+        continue;
+      }
+      column_count++;
+
       const NdbRecord::Attr *col= &rec->columns[rec_pos];
 
       /* We should never get back an attribute not originally requested. */
-      assert(rec_pos < rec->noOfColumns &&
-             col->attrId == attrId);
+      assert(rec_pos < rec->noOfColumns && col->attrId == attrId);
 
       /* The fast path is for a plain offset/length column (not blob eg). */
       if (likely(!(col->flags & (NdbRecord::IsBlob|NdbRecord::IsMysqldBitfield))))
@@ -634,7 +664,7 @@ NdbReceiver::execTRANSID_AI(const Uint32
         else
         {
           /* Blob head. */
-          receiveBlobHead(rec, rec_pos, aDataPtr, attrSize, blob_pos);
+          receiveBlobHead(rec, rec_pos, aDataPtr, attrSize, save_pos);
           Uint32 sizeInWords= (attrSize+3)>>2;
           aDataPtr+= sizeInWords;
           aLength-= sizeInWords;
@@ -650,7 +680,7 @@ NdbReceiver::execTRANSID_AI(const Uint32
   }
 
   /* The old way, using getValue() and NdbRecAttr. */
-  NdbRecAttr* currRecAttr = m_recattr.theCurrentRecAttr;
+  NdbRecAttr* currRecAttr = theCurrentRecAttr;
   
   for (Uint32 used = 0; used < aLength ; used++){
     AttributeHeader ah(* aDataPtr++);
@@ -688,9 +718,9 @@ NdbReceiver::execTRANSID_AI(const Uint32
       */
       ndbout_c("this=%p: tAttrId: %d currRecAttr: %p theCurrentRecAttr: %p "
                "tAttrSize: %d %d", this,
-	       tAttrId, currRecAttr, m_recattr.theCurrentRecAttr, tAttrSize,
+	       tAttrId, currRecAttr, theCurrentRecAttr, tAttrSize,
                currRecAttr ? currRecAttr->get_size_in_bytes() : 0);
-      currRecAttr = m_recattr.theCurrentRecAttr;
+      currRecAttr = theCurrentRecAttr;
       while(currRecAttr != 0){
 	ndbout_c("%d ", currRecAttr->attrId());
 	currRecAttr = currRecAttr->next();
@@ -700,7 +730,7 @@ NdbReceiver::execTRANSID_AI(const Uint32
     }
   }
 
-  m_recattr.theCurrentRecAttr = currRecAttr;
+  theCurrentRecAttr = currRecAttr;
   
   /**
    * Update m_received_result_length

--- 1.115/storage/ndb/src/ndbapi/NdbScanOperation.cpp	2007-05-08 12:28:55 +02:00
+++ 1.116/storage/ndb/src/ndbapi/NdbScanOperation.cpp	2007-05-08 12:28:55 +02:00
@@ -479,7 +479,9 @@ NdbScanOperation::nextResult(const char 
   }
 
   if ((res = nextResultNdbRecord(out_row, fetchAllowed, forceSend)) == 0) {
-    if (unlikely(theBlobList != NULL))
+    NdbBlob* tBlob= theBlobList;
+    NdbRecAttr *getvalue_recattr= theReceiver.theFirstRecAttr;
+    if (unlikely(((UintPtr)tBlob | (UintPtr)getvalue_recattr) != 0))
     {
       /* Handle blobs. */
 
@@ -487,30 +489,45 @@ NdbScanOperation::nextResult(const char 
       Uint32 idx= m_current_api_receiver;
       assert(idx < m_api_receivers_count);
       const NdbReceiver *receiver= m_api_receivers[m_current_api_receiver];
-      Uint32 infoword;                          // Not used for blobs
-      Uint32 key_length;
-      const char *key_data;
-      res= receiver->get_keyinfo20(infoword, key_length, key_data);
-      if (res == -1)
-        return -1;
-
-      NdbBlob* tBlob= theBlobList;
       Uint32 blob_pos= 0;
-      while (tBlob != 0)
+
+      if (tBlob)
       {
-        const char *blobhead_data;
-        Uint32 blobhead_size;
-        if (receiver->getBlobHead(blobhead_data, blobhead_size, blob_pos) == -1)
+        Uint32 infoword;                          // Not used for blobs
+        Uint32 key_length;
+        const char *key_data;
+        res= receiver->get_keyinfo20(infoword, key_length, key_data);
+        if (res == -1)
           return -1;
-        tBlob->receiveHead(blobhead_data, blobhead_size);
 
-        if (tBlob->atNextResultNdbRecord(key_data, key_length*4) == -1)
+        do
+        {
+          const char *blobhead_data;
+          Uint32 blobhead_size;
+          if (receiver->getScanAttrData(blobhead_data, blobhead_size, blob_pos) == -1)
+            return -1;
+          tBlob->receiveHead(blobhead_data, blobhead_size);
+
+          if (tBlob->atNextResultNdbRecord(key_data, key_length*4) == -1)
+            return -1;
+          tBlob= tBlob->theNext;
+        } while (tBlob != 0);
+        /* Flush blob part ops on behalf of user. */
+        if (m_transConnection->executePendingBlobOps() == -1)
           return -1;
-        tBlob= tBlob->theNext;
       }
-      /* Flush blob part ops on behalf of user. */
-      if (m_transConnection->executePendingBlobOps() == -1)
-        return -1;
+
+      while (getvalue_recattr != NULL)
+      {
+        const char *attr_data;
+        Uint32 attr_size;
+        if (receiver->getScanAttrData(attr_data, attr_size, blob_pos) == -1)
+          return -1;
+        if (!getvalue_recattr->receive_data((const Uint32 *)attr_data,
+                                            attr_size))
+          return -1;                            // purecov: deadcode
+        getvalue_recattr= getvalue_recattr->next();
+      }
     }
     return 0;
   }
@@ -1057,8 +1074,10 @@ int NdbScanOperation::prepareSendScan(Ui
   if (theStatus == UseNdbRecord)
   {
     Uint32 blobs_size= 0;
-    if (m_attribute_record->flags & NdbRecord::RecHasBlob)
+    if (unlikely(m_attribute_record->flags & NdbRecord::RecHasBlob))
       blobs_size= calcBlobsSize();
+    if (unlikely(theReceiver.theFirstRecAttr != NULL))
+      blobs_size+= calcGetValueSize();
 
     assert(theParallelism > 0);
     Uint32 rowsize= m_receivers[0]->ndbrecord_rowsize(m_attribute_record,
@@ -1079,7 +1098,8 @@ int NdbScanOperation::prepareSendScan(Ui
     {
       m_receivers[i]->do_setup_ndbrecord(m_attribute_record, batch_size,
                                          key_size, m_read_range_no,
-                                         rowsize, buf);
+                                         rowsize, buf,
+                                         theReceiver.m_record.m_column_count);
       buf+= bufsize;
     }
   }
@@ -1131,6 +1151,24 @@ NdbScanOperation::calcBlobsSize()
   return size;
 }
 
+/*
+  Compute extra space needed to buffer getValue() results in NdbRecord
+  scans.
+ */
+Uint32
+NdbScanOperation::calcGetValueSize()
+{
+  Uint32 size= 0;
+  const NdbRecAttr *ra= theReceiver.theFirstRecAttr;
+  while (ra != NULL)
+  {
+    Uint32 thisSize= ra->getColumn()->getSizeInBytes();
+    size+= (thisSize + (4+3)) & (~3);
+    ra= ra->next();
+  }
+  return size;
+}
+
 /*****************************************************************************
 int doSend()
 
@@ -1498,6 +1536,37 @@ NdbScanOperation::getBlobHandle(Uint32 a
 				     m_currentTable->getColumn(anAttrId));
 }
 
+NdbRecAttr*
+NdbScanOperation::getValue_NdbRecord_scan(const NdbColumnImpl* attrInfo,
+                                          char* aValue)
+{
+  int res;
+  Uint32 ah;
+  NdbRecAttr *ra;
+  AttributeHeader::init(&ah, attrInfo->m_attrId, 0);
+  res= insertATTRINFO(ah);
+  if (res==-1)
+    return NULL;
+  theInitialReadSize= theTotalCurrAI_Len - 5;
+  ra= theReceiver.getValue(attrInfo, aValue);
+  if (!ra)
+  {
+    setErrorCodeAbort(4000);
+    return NULL;
+  }
+  theErrorLine++;
+  return ra;
+}
+
+NdbRecAttr*
+NdbScanOperation::getValue_impl(const NdbColumnImpl *attrInfo, char *aValue)
+{
+  if (theStatus == UseNdbRecord)
+    return getValue_NdbRecord_scan(attrInfo, aValue);
+  else
+    return NdbOperation::getValue_impl(attrInfo, aValue);
+}
+
 NdbIndexScanOperation::NdbIndexScanOperation(Ndb* aNdb)
   : NdbScanOperation(aNdb, NdbOperation::OrderedIndexScan)
 {
@@ -1530,6 +1599,9 @@ NdbIndexScanOperation::equal_impl(const 
 NdbRecAttr*
 NdbIndexScanOperation::getValue_impl(const NdbColumnImpl* attrInfo, 
 				     char* aValue){
+  if (theStatus == UseNdbRecord)
+    return getValue_NdbRecord_scan(attrInfo, aValue);
+
   if(!m_ordered){
     return NdbScanOperation::getValue_impl(attrInfo, aValue);
   }
@@ -1858,7 +1930,7 @@ NdbIndexScanOperation::fix_get_values(){
   /**
    * Loop through all getValues and set buffer pointer to "API" pointer
    */
-  NdbRecAttr * curr = theReceiver.m_recattr.theFirstRecAttr;
+  NdbRecAttr * curr = theReceiver.theFirstRecAttr;
   Uint32 cnt = m_accessTable->getNoOfColumns() - 1;
   assert(cnt <  NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY);
   
Thread
bk commit into 5.1 tree (knielsen:1.2506)knielsen8 May