List:Commits« Previous MessageNext Message »
From:knielsen Date:March 12 2007 7:43am
Subject:bk commit into 5.1 tree (knielsen:1.2482)
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-03-12 08:42:59+01:00, knielsen@ymer.(none) +2 -0
  Merge ymer.(none):/usr/local/mysql/mysql-5.0-ndb
  into  ymer.(none):/usr/local/mysql/mysql-5.1-new-ndb
  MERGE: 1.1810.2636.23

  storage/ndb/src/ndbapi/NdbBlob.cpp@stripped, 2007-03-12 08:42:55+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.22.11.2

  storage/ndb/src/ndbapi/NdbBlob.cpp@stripped, 2007-03-12 08:42:55+01:00, knielsen@ymer.(none) +0 -0
    Merge rename: ndb/src/ndbapi/NdbBlob.cpp -> storage/ndb/src/ndbapi/NdbBlob.cpp

  storage/ndb/test/ndbapi/testBlobs.cpp@stripped, 2007-03-12 08:42:55+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.20.15.2

  storage/ndb/test/ndbapi/testBlobs.cpp@stripped, 2007-03-12 08:42:55+01:00, knielsen@ymer.(none) +0 -0
    Merge rename: ndb/test/ndbapi/testBlobs.cpp -> storage/ndb/test/ndbapi/testBlobs.cpp

# 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-new-ndb/RESYNC

--- 1.20.15.1/ndb/test/ndbapi/testBlobs.cpp	2007-03-12 08:43:07 +01:00
+++ 1.36/storage/ndb/test/ndbapi/testBlobs.cpp	2007-03-12 08:43:07 +01:00
@@ -735,7 +735,7 @@ verifyHeadInline(const Tup& tup)
   if (! g_opt.m_oneblob)
     CHK((ra2 = g_opr->getValue("BL2")) != 0);
   if (tup.m_exists) {
-    CHK(g_con->execute(Commit) == 0);
+    CHK(g_con->execute(Commit, AbortOnError) == 0);
     DBG("verifyHeadInline BL1");
     CHK(verifyHeadInline(g_opt.m_blob1, tup.m_blob1, ra1) == 0);
     if (! g_opt.m_oneblob) {
@@ -743,7 +743,8 @@ verifyHeadInline(const Tup& tup)
       CHK(verifyHeadInline(g_opt.m_blob2, tup.m_blob2, ra2) == 0);
     }
   } else {
-    CHK(g_con->execute(Commit) == -1 && g_con->getNdbError().code == 626);
+    CHK(g_con->execute(Commit, AbortOnError) == -1 && 
+	g_con->getNdbError().code == 626);
   }
   g_ndb->closeTransaction(g_con);
   g_opr = 0;
@@ -1535,7 +1536,7 @@ testperf()
   g_dic = g_ndb->getDictionary();
   NdbDictionary::Table tab(g_opt.m_tnameperf);
   if (g_dic->getTable(tab.getName()) != 0)
-    CHK(g_dic->dropTable(tab) == 0);
+    CHK(g_dic->dropTable(tab.getName()) == 0);
   // col A - pk
   { NdbDictionary::Column col("A");
     col.setType(NdbDictionary::Column::Unsigned);

--- 1.22.11.1/ndb/src/ndbapi/NdbBlob.cpp	2007-03-12 08:43:07 +01:00
+++ 1.53/storage/ndb/src/ndbapi/NdbBlob.cpp	2007-03-12 08:43:07 +01:00
@@ -23,6 +23,7 @@
 #include "NdbBlobImpl.hpp"
 #include <NdbScanOperation.hpp>
 #include <signaldata/TcKeyReq.hpp>
+#include <NdbEventOperationImpl.hpp>
 
 /*
  * Reading index table directly (as a table) is faster but there are
@@ -30,7 +31,21 @@
  */
 static const bool g_ndb_blob_ok_to_read_index_table = false;
 
-// state (inline)
+// get state
+
+NdbBlob::State
+NdbBlob::getState()
+{
+  return theState;
+}
+
+void
+NdbBlob::getVersion(int& version)
+{
+  version = theEventBlobVersion;
+}
+
+// set state (inline)
 
 inline void
 NdbBlob::setState(State newState)
@@ -46,32 +61,72 @@ NdbBlob::setState(State newState)
 int
 NdbBlob::getBlobTableName(char* btname, Ndb* anNdb, const char* tableName, const char* columnName)
 {
+  DBUG_ENTER("NdbBlob::getBlobTableName");
   NdbTableImpl* t = anNdb->theDictionary->m_impl.getTable(tableName);
   if (t == NULL)
-    return -1;
+    DBUG_RETURN(-1);
   NdbColumnImpl* c = t->getColumn(columnName);
   if (c == NULL)
-    return -1;
+    DBUG_RETURN(-1);
   getBlobTableName(btname, t, c);
-  return 0;
+  DBUG_RETURN(0);
 }
 
 void
 NdbBlob::getBlobTableName(char* btname, const NdbTableImpl* t, const NdbColumnImpl* c)
 {
-  assert(t != 0 && c != 0 && c->getBlobType());
+  DBUG_ENTER("NdbBlob::getBlobTableName");
+  assert(t != 0 && c != 0 && c->getBlobType() && c->getPartSize() != 0);
   memset(btname, 0, NdbBlobImpl::BlobTableNameSize);
-  sprintf(btname, "NDB$BLOB_%d_%d", (int)t->m_tableId, (int)c->m_attrId);
+  sprintf(btname, "NDB$BLOB_%d_%d", (int)t->m_id, (int)c->m_column_no);
+  DBUG_PRINT("info", ("blob table name: %s", btname));
+  DBUG_VOID_RETURN;
 }
 
 void
 NdbBlob::getBlobTable(NdbTableImpl& bt, const NdbTableImpl* t, const NdbColumnImpl* c)
 {
+  DBUG_ENTER("NdbBlob::getBlobTable");
   char btname[NdbBlobImpl::BlobTableNameSize];
   getBlobTableName(btname, t, c);
   bt.setName(btname);
   bt.setLogging(t->getLogging());
-  bt.setFragmentType(t->getFragmentType());
+  /*
+    BLOB tables use the same fragmentation as the original table
+    but may change the fragment type if it is UserDefined since it
+    must be hash based so that the kernel can handle it on its own.
+    It also uses the same tablespaces and it never uses any range or
+    list arrays.
+  */
+  bt.m_primaryTableId = t->m_id;
+  bt.m_fd.clear();
+  bt.m_ts.clear();
+  bt.m_range.clear();
+  bt.setFragmentCount(t->getFragmentCount());
+  bt.m_tablespace_id = t->m_tablespace_id;
+  bt.m_tablespace_version = t->m_tablespace_version;
+  switch (t->getFragmentType())
+  {
+    case NdbDictionary::Object::FragAllSmall:
+    case NdbDictionary::Object::FragAllMedium:
+    case NdbDictionary::Object::FragAllLarge:
+    case NdbDictionary::Object::FragSingle:
+      bt.setFragmentType(t->getFragmentType());
+      break;
+    case NdbDictionary::Object::DistrKeyLin:
+    case NdbDictionary::Object::DistrKeyHash:
+      bt.setFragmentType(t->getFragmentType());
+      break;
+    case NdbDictionary::Object::UserDefined:
+      bt.setFragmentType(NdbDictionary::Object::DistrKeyHash);
+      break;
+    default:
+      DBUG_ASSERT(0);
+      break;
+  }
+  DBUG_PRINT("info",
+  ("Create BLOB table with primary table = %u and Fragment Type = %u",
+    bt.m_primaryTableId, (uint)bt.getFragmentType()));
   { NdbDictionary::Column bc("PK");
     bc.setType(NdbDictionary::Column::Unsigned);
     assert(t->m_keyLenInWords != 0);
@@ -105,8 +160,67 @@ NdbBlob::getBlobTable(NdbTableImpl& bt, 
       break;
     }
     bc.setLength(c->getPartSize());
+    bc.setStorageType(c->getStorageType());
     bt.addColumn(bc);
   }
+  DBUG_VOID_RETURN;
+}
+
+int
+NdbBlob::getBlobEventName(char* bename, Ndb* anNdb, const char* eventName, const char* columnName)
+{
+  NdbEventImpl* e = anNdb->theDictionary->m_impl.getEvent(eventName);
+  if (e == NULL)
+    return -1;
+  NdbColumnImpl* c = e->m_tableImpl->getColumn(columnName);
+  if (c == NULL)
+    return -1;
+  getBlobEventName(bename, e, c);
+  delete e; // it is from new NdbEventImpl
+  return 0;
+}
+
+void
+NdbBlob::getBlobEventName(char* bename, const NdbEventImpl* e, const NdbColumnImpl* c)
+{
+  // XXX events should have object id
+  snprintf(bename, MAX_TAB_NAME_SIZE, "NDB$BLOBEVENT_%s_%d", e->m_name.c_str(), (int)c->m_column_no);
+}
+
+void
+NdbBlob::getBlobEvent(NdbEventImpl& be, const NdbEventImpl* e, const NdbColumnImpl* c)
+{
+  DBUG_ENTER("NdbBlob::getBlobEvent");
+  // blob table
+  assert(c->m_blobTable != NULL);
+  const NdbTableImpl& bt = *c->m_blobTable;
+  // blob event name
+  char bename[MAX_TAB_NAME_SIZE+1];
+  getBlobEventName(bename, e, c);
+  bename[sizeof(bename)-1]= 0;
+  be.setName(bename);
+  be.setTable(bt);
+  // simple assigments
+  be.mi_type = e->mi_type;
+  be.m_dur = e->m_dur;
+  be.m_mergeEvents = e->m_mergeEvents;
+  // report unchanged data
+  // not really needed now since UPD is DEL o INS and we subscribe to all
+  be.setReport(NdbDictionary::Event::ER_ALL);
+  // columns PK - DIST - PART - DATA
+  { const NdbColumnImpl* bc = bt.getColumn((Uint32)0);
+    be.addColumn(*bc);
+  }
+  { const NdbColumnImpl* bc = bt.getColumn((Uint32)1);
+    be.addColumn(*bc);
+  }
+  { const NdbColumnImpl* bc = bt.getColumn((Uint32)2);
+    be.addColumn(*bc);
+  }
+  { const NdbColumnImpl* bc = bt.getColumn((Uint32)3);
+    be.addColumn(*bc);
+  }
+  DBUG_VOID_RETURN;
 }
 
 // initialization
@@ -120,9 +234,16 @@ void
 NdbBlob::init()
 {
   theState = Idle;
+  theEventBlobVersion = -1;
   theNdb = NULL;
   theNdbCon = NULL;
   theNdbOp = NULL;
+  theEventOp = NULL;
+  theBlobEventOp = NULL;
+  theBlobEventPkRecAttr = NULL;
+  theBlobEventDistRecAttr = NULL;
+  theBlobEventPartRecAttr = NULL;
+  theBlobEventDataRecAttr = NULL;
   theTable = NULL;
   theAccessTable = NULL;
   theBlobTable = NULL;
@@ -188,9 +309,16 @@ NdbBlob::Buf::alloc(unsigned n)
 }
 
 void
+NdbBlob::Buf::zerorest()
+{
+  assert(size <= maxsize);
+  memset(data + size, 0, maxsize - size);
+}
+
+void
 NdbBlob::Buf::copyfrom(const NdbBlob::Buf& src)
 {
-  assert(size == src.size);
+  size = src.size;
   memcpy(data, src.data, size);
 }
 
@@ -305,6 +433,76 @@ NdbBlob::getDistKey(Uint32 part)
   return (part / theStripeSize) % theStripeSize;
 }
 
+// pack/unpack table/index key  XXX support routines, shortcuts
+
+int
+NdbBlob::packKeyValue(const NdbTableImpl* aTable, const Buf& srcBuf)
+{
+  DBUG_ENTER("NdbBlob::packKeyValue");
+  const Uint32* data = (const Uint32*)srcBuf.data;
+  unsigned pos = 0;
+  Uint32* pack_data = (Uint32*)thePackKeyBuf.data;
+  unsigned pack_pos = 0;
+  for (unsigned i = 0; i < aTable->m_columns.size(); i++) {
+    NdbColumnImpl* c = aTable->m_columns[i];
+    assert(c != NULL);
+    if (c->m_pk) {
+      unsigned len = c->m_attrSize * c->m_arraySize;
+      Uint32 pack_len;
+      bool ok = c->get_var_length(&data[pos], pack_len);
+      if (! ok) {
+        setErrorCode(NdbBlobImpl::ErrCorruptPK);
+        DBUG_RETURN(-1);
+      }
+      memcpy(&pack_data[pack_pos], &data[pos], pack_len);
+      while (pack_len % 4 != 0) {
+        char* p = (char*)&pack_data[pack_pos] + pack_len++;
+        *p = 0;
+      }
+      pos += (len + 3) / 4;
+      pack_pos += pack_len / 4;
+    }
+  }
+  assert(4 * pos == srcBuf.size);
+  assert(4 * pack_pos <= thePackKeyBuf.maxsize);
+  thePackKeyBuf.size = 4 * pack_pos;
+  thePackKeyBuf.zerorest();
+  DBUG_RETURN(0);
+}
+
+int
+NdbBlob::unpackKeyValue(const NdbTableImpl* aTable, Buf& dstBuf)
+{
+  DBUG_ENTER("NdbBlob::unpackKeyValue");
+  Uint32* data = (Uint32*)dstBuf.data;
+  unsigned pos = 0;
+  const Uint32* pack_data = (const Uint32*)thePackKeyBuf.data;
+  unsigned pack_pos = 0;
+  for (unsigned i = 0; i < aTable->m_columns.size(); i++) {
+    NdbColumnImpl* c = aTable->m_columns[i];
+    assert(c != NULL);
+    if (c->m_pk) {
+      unsigned len = c->m_attrSize * c->m_arraySize;
+      Uint32 pack_len;
+      bool ok = c->get_var_length(&pack_data[pack_pos], pack_len);
+      if (! ok) {
+        setErrorCode(NdbBlobImpl::ErrCorruptPK);
+        DBUG_RETURN(-1);
+      }
+      memcpy(&data[pos], &pack_data[pack_pos], pack_len);
+      while (pack_len % 4 != 0) {
+        char* p = (char*)&data[pos] + pack_len++;
+        *p = 0;
+      }
+      pos += (len + 3) / 4;
+      pack_pos += pack_len / 4;
+    }
+  }
+  assert(4 * pos == dstBuf.size);
+  assert(4 * pack_pos == thePackKeyBuf.size);
+  DBUG_RETURN(0);
+}
+
 // getters and setters
 
 int
@@ -347,13 +545,15 @@ NdbBlob::setTableKeyValue(NdbOperation* 
     assert(c != NULL);
     if (c->m_pk) {
       unsigned len = c->m_attrSize * c->m_arraySize;
-      if (anOp->equal_impl(c, (const char*)&data[pos], len) == -1) {
+      if (anOp->equal_impl(c, (const char*)&data[pos]) == -1) {
         setErrorCode(anOp);
         DBUG_RETURN(-1);
       }
       pos += (len + 3) / 4;
     }
   }
+  if (theNdbOp->theDistrKeyIndicator_)
+    anOp->setPartitionId(theNdbOp->getPartitionId());
   assert(pos == theKeyBuf.size / 4);
   DBUG_RETURN(0);
 }
@@ -371,7 +571,7 @@ NdbBlob::setAccessKeyValue(NdbOperation*
     assert(c != NULL);
     if (c->m_pk) {
       unsigned len = c->m_attrSize * c->m_arraySize;
-      if (anOp->equal_impl(c, (const char*)&data[pos], len) == -1) {
+      if (anOp->equal_impl(c, (const char*)&data[pos]) == -1) {
         setErrorCode(anOp);
         DBUG_RETURN(-1);
       }
@@ -386,10 +586,10 @@ int
 NdbBlob::setPartKeyValue(NdbOperation* anOp, Uint32 part)
 {
   DBUG_ENTER("NdbBlob::setPartKeyValue");
-  DBUG_PRINT("info", ("dist=%u part=%u key=", getDistKey(part), part));
-  DBUG_DUMP("info", theKeyBuf.data, 4 * theTable->m_keyLenInWords);
+  DBUG_PRINT("info", ("dist=%u part=%u packkey=", getDistKey(part), part));
+  DBUG_DUMP("info", thePackKeyBuf.data, 4 * thePackKeyBuf.size);
   // TODO use attr ids after compatibility with 4.1.7 not needed
-  if (anOp->equal("PK", theKeyBuf.data) == -1 ||
+  if (anOp->equal("PK", thePackKeyBuf.data) == -1 ||
       anOp->equal("DIST", getDistKey(part)) == -1 ||
       anOp->equal("PART", part) == -1) {
     setErrorCode(anOp);
@@ -416,8 +616,10 @@ NdbBlob::getHeadFromRecAttr()
   DBUG_ENTER("NdbBlob::getHeadFromRecAttr");
   assert(theHeadInlineRecAttr != NULL);
   theNullFlag = theHeadInlineRecAttr->isNULL();
-  assert(theNullFlag != -1);
+  assert(theEventBlobVersion >= 0 || theNullFlag != -1);
   theLength = ! theNullFlag ? theHead->length : 0;
+  DBUG_PRINT("info", ("theNullFlag=%d theLength=%llu",
+                      theNullFlag, theLength));
   DBUG_VOID_RETURN;
 }
 
@@ -430,7 +632,7 @@ NdbBlob::setHeadInlineValue(NdbOperation
     memset(theInlineData + theLength, 0, theInlineSize - theLength);
   assert(theNullFlag != -1);
   const char* aValue = theNullFlag ? 0 : theHeadInlineBuf.data;
-  if (anOp->setValue(theColumn, aValue, theHeadInlineBuf.size) == -1) {
+  if (anOp->setValue(theColumn, aValue) == -1) {
     setErrorCode(anOp);
     DBUG_RETURN(-1);
   }
@@ -521,7 +723,19 @@ NdbBlob::setActiveHook(ActiveHook active
 // misc operations
 
 int
-NdbBlob::getNull(bool& isNull)
+NdbBlob::getDefined(int& isNull) // deprecated
+{
+  DBUG_ENTER("NdbBlob::getDefined");
+  if (theState == Prepared && theSetFlag) {
+    isNull = (theSetBuf == NULL);
+    DBUG_RETURN(0);
+  }
+  isNull = theNullFlag;
+  DBUG_RETURN(0);
+}
+
+int
+NdbBlob::getNull(bool& isNull) // deprecated
 {
   DBUG_ENTER("NdbBlob::getNull");
   if (theState == Prepared && theSetFlag) {
@@ -537,6 +751,23 @@ NdbBlob::getNull(bool& isNull)
 }
 
 int
+NdbBlob::getNull(int& isNull)
+{
+  DBUG_ENTER("NdbBlob::getNull");
+  if (theState == Prepared && theSetFlag) {
+    isNull = (theSetBuf == NULL);
+    DBUG_RETURN(0);
+  }
+  isNull = theNullFlag;
+  if (isNull == -1 && theEventBlobVersion == -1) {
+    setErrorCode(NdbBlobImpl::ErrState);
+    DBUG_RETURN(-1);
+  }
+  DBUG_PRINT("info", ("isNull=%d", isNull));
+  DBUG_RETURN(0);
+}
+
+int
 NdbBlob::setNull()
 {
   DBUG_ENTER("NdbBlob::setNull");
@@ -882,6 +1113,18 @@ NdbBlob::readParts(char* buf, Uint32 par
 {
   DBUG_ENTER("NdbBlob::readParts");
   DBUG_PRINT("info", ("part=%u count=%u", part, count));
+  int ret;
+  if (theEventBlobVersion == -1)
+    ret = readTableParts(buf, part, count);
+  else
+    ret = readEventParts(buf, part, count);
+  DBUG_RETURN(ret);
+}
+
+int
+NdbBlob::readTableParts(char* buf, Uint32 part, Uint32 count)
+{
+  DBUG_ENTER("NdbBlob::readTableParts");
   Uint32 n = 0;
   while (n < count) {
     NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable);
@@ -892,7 +1135,7 @@ NdbBlob::readParts(char* buf, Uint32 par
       setErrorCode(tOp);
       DBUG_RETURN(-1);
     }
-    tOp->m_abortOption = NdbTransaction::AbortOnError;
+    tOp->m_abortOption = NdbOperation::AbortOnError;
     buf += thePartSize;
     n++;
     thePendingBlobOps |= (1 << NdbOperation::ReadRequest);
@@ -902,6 +1145,18 @@ NdbBlob::readParts(char* buf, Uint32 par
 }
 
 int
+NdbBlob::readEventParts(char* buf, Uint32 part, Uint32 count)
+{
+  DBUG_ENTER("NdbBlob::readEventParts");
+  int ret = theEventOp->readBlobParts(buf, this, part, count);
+  if (ret != 0) {
+    setErrorCode(theEventOp);
+    DBUG_RETURN(-1);
+  }
+  DBUG_RETURN(0);
+}
+
+int
 NdbBlob::insertParts(const char* buf, Uint32 part, Uint32 count)
 {
   DBUG_ENTER("NdbBlob::insertParts");
@@ -916,7 +1171,7 @@ NdbBlob::insertParts(const char* buf, Ui
       setErrorCode(tOp);
       DBUG_RETURN(-1);
     }
-    tOp->m_abortOption = NdbTransaction::AbortOnError;
+    tOp->m_abortOption = NdbOperation::AbortOnError;
     buf += thePartSize;
     n++;
     thePendingBlobOps |= (1 << NdbOperation::InsertRequest);
@@ -940,7 +1195,7 @@ NdbBlob::updateParts(const char* buf, Ui
       setErrorCode(tOp);
       DBUG_RETURN(-1);
     }
-    tOp->m_abortOption = NdbTransaction::AbortOnError;
+    tOp->m_abortOption = NdbOperation::AbortOnError;
     buf += thePartSize;
     n++;
     thePendingBlobOps |= (1 << NdbOperation::UpdateRequest);
@@ -963,7 +1218,7 @@ NdbBlob::deleteParts(Uint32 part, Uint32
       setErrorCode(tOp);
       DBUG_RETURN(-1);
     }
-    tOp->m_abortOption = NdbTransaction::AbortOnError;
+    tOp->m_abortOption = NdbOperation::AbortOnError;
     n++;
     thePendingBlobOps |= (1 << NdbOperation::DeleteRequest);
     theNdbCon->thePendingBlobOps |= (1 << NdbOperation::DeleteRequest);
@@ -999,7 +1254,7 @@ NdbBlob::deletePartsUnknown(Uint32 part)
         setErrorCode(tOp);
         DBUG_RETURN(-1);
       }
-      tOp->m_abortOption= NdbTransaction::AO_IgnoreError;
+      tOp->m_abortOption= NdbOperation::AO_IgnoreError;
       n++;
     }
     DBUG_PRINT("info", ("bat=%u", bat));
@@ -1091,68 +1346,40 @@ NdbBlob::atPrepare(NdbTransaction* aCon,
   theTable = anOp->m_currentTable;
   theAccessTable = anOp->m_accessTable;
   theColumn = aColumn;
-  NdbDictionary::Column::Type partType = NdbDictionary::Column::Undefined;
-  switch (theColumn->getType()) {
-  case NdbDictionary::Column::Blob:
-    partType = NdbDictionary::Column::Binary;
-    theFillChar = 0x0;
-    break;
-  case NdbDictionary::Column::Text:
-    partType = NdbDictionary::Column::Char;
-    theFillChar = 0x20;
-    break;
-  default:
-    setErrorCode(NdbBlobImpl::ErrUsage);
+  // prepare blob column and table
+  if (prepareColumn() == -1)
     DBUG_RETURN(-1);
-  }
-  // sizes
-  theInlineSize = theColumn->getInlineSize();
-  thePartSize = theColumn->getPartSize();
-  theStripeSize = theColumn->getStripeSize();
-  // sanity check
-  assert((NDB_BLOB_HEAD_SIZE << 2) == sizeof(Head));
-  assert(theColumn->m_attrSize * theColumn->m_arraySize == sizeof(Head) + theInlineSize);
-  if (thePartSize > 0) {
-    const NdbDictionary::Table* bt = NULL;
-    const NdbDictionary::Column* bc = NULL;
-    if (theStripeSize == 0 ||
-        (bt = theColumn->getBlobTable()) == NULL ||
-        (bc = bt->getColumn("DATA")) == NULL ||
-        bc->getType() != partType ||
-        bc->getLength() != (int)thePartSize) {
-      setErrorCode(NdbBlobImpl::ErrTable);
-      DBUG_RETURN(-1);
-    }
-    theBlobTable = &NdbTableImpl::getImpl(*bt);
-  }
-  // buffers
-  theKeyBuf.alloc(theTable->m_keyLenInWords << 2);
+  // extra buffers
   theAccessKeyBuf.alloc(theAccessTable->m_keyLenInWords << 2);
-  theHeadInlineBuf.alloc(sizeof(Head) + theInlineSize);
   theHeadInlineCopyBuf.alloc(sizeof(Head) + theInlineSize);
-  thePartBuf.alloc(thePartSize);
-  theHead = (Head*)theHeadInlineBuf.data;
-  theInlineData = theHeadInlineBuf.data + sizeof(Head);
   // handle different operation types
   bool supportedOp = false;
   if (isKeyOp()) {
     if (isTableOp()) {
       // get table key
-      Uint32* data = (Uint32*)theKeyBuf.data;
-      unsigned size = theTable->m_keyLenInWords;
+      Uint32* data = (Uint32*)thePackKeyBuf.data;
+      Uint32 size = theTable->m_keyLenInWords; // in-out
       if (theNdbOp->getKeyFromTCREQ(data, size) == -1) {
         setErrorCode(NdbBlobImpl::ErrUsage);
         DBUG_RETURN(-1);
       }
+      thePackKeyBuf.size = 4 * size;
+      thePackKeyBuf.zerorest();
+      if (unpackKeyValue(theTable, theKeyBuf) == -1)
+        DBUG_RETURN(-1);
     }
     if (isIndexOp()) {
       // get index key
-      Uint32* data = (Uint32*)theAccessKeyBuf.data;
-      unsigned size = theAccessTable->m_keyLenInWords;
+      Uint32* data = (Uint32*)thePackKeyBuf.data;
+      Uint32 size = theAccessTable->m_keyLenInWords; // in-out
       if (theNdbOp->getKeyFromTCREQ(data, size) == -1) {
         setErrorCode(NdbBlobImpl::ErrUsage);
         DBUG_RETURN(-1);
       }
+      thePackKeyBuf.size = 4 * size;
+      thePackKeyBuf.zerorest();
+      if (unpackKeyValue(theAccessTable, theAccessKeyBuf) == -1)
+        DBUG_RETURN(-1);
     }
     if (isReadOp()) {
       // upgrade lock mode
@@ -1192,6 +1419,105 @@ NdbBlob::atPrepare(NdbTransaction* aCon,
   DBUG_RETURN(0);
 }
 
+int
+NdbBlob::atPrepare(NdbEventOperationImpl* anOp, NdbEventOperationImpl* aBlobOp, const NdbColumnImpl* aColumn, int version)
+{
+  DBUG_ENTER("NdbBlob::atPrepare [event]");
+  DBUG_PRINT("info", ("this=%p op=%p", this, anOp));
+  assert(theState == Idle);
+  assert(version == 0 || version == 1);
+  theEventBlobVersion = version;
+  // ndb api stuff
+  theNdb = anOp->m_ndb;
+  theEventOp = anOp;
+  theBlobEventOp = aBlobOp;
+  theTable = anOp->m_eventImpl->m_tableImpl;
+  theAccessTable = theTable;
+  theColumn = aColumn;
+  // prepare blob column and table
+  if (prepareColumn() == -1)
+    DBUG_RETURN(-1);
+  // tinyblob sanity
+  assert((theBlobEventOp == NULL) == (theBlobTable == NULL));
+  // extra buffers
+  theBlobEventDataBuf.alloc(thePartSize);
+  // prepare receive of head+inline
+  theHeadInlineRecAttr = theEventOp->getValue(aColumn, theHeadInlineBuf.data, version);
+  if (theHeadInlineRecAttr == NULL) {
+    setErrorCode(theEventOp);
+    DBUG_RETURN(-1);
+  }
+  // prepare receive of blob part
+  if (theBlobEventOp != NULL) {
+    if ((theBlobEventPkRecAttr =
+           theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)0),
+                                    thePackKeyBuf.data, version)) == NULL ||
+        (theBlobEventDistRecAttr =
+           theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)1),
+                                    (char*)0, version)) == NULL ||
+        (theBlobEventPartRecAttr =
+           theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)2),
+                                    (char*)&thePartNumber, version)) == NULL ||
+        (theBlobEventDataRecAttr =
+           theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)3),
+                                    theBlobEventDataBuf.data, version)) == NULL) {
+      setErrorCode(theBlobEventOp);
+      DBUG_RETURN(-1);
+    }
+  }
+  setState(Prepared);
+  DBUG_RETURN(0);
+}
+
+int
+NdbBlob::prepareColumn()
+{
+  DBUG_ENTER("prepareColumn");
+  NdbDictionary::Column::Type partType = NdbDictionary::Column::Undefined;
+  switch (theColumn->getType()) {
+  case NdbDictionary::Column::Blob:
+    partType = NdbDictionary::Column::Binary;
+    theFillChar = 0x0;
+    break;
+  case NdbDictionary::Column::Text:
+    partType = NdbDictionary::Column::Char;
+    theFillChar = 0x20;
+    break;
+  default:
+    setErrorCode(NdbBlobImpl::ErrUsage);
+    DBUG_RETURN(-1);
+  }
+  // sizes
+  theInlineSize = theColumn->getInlineSize();
+  thePartSize = theColumn->getPartSize();
+  theStripeSize = theColumn->getStripeSize();
+  // sanity check
+  assert((NDB_BLOB_HEAD_SIZE << 2) == sizeof(Head));
+  assert(theColumn->m_attrSize * theColumn->m_arraySize == sizeof(Head) + theInlineSize);
+  if (thePartSize > 0) {
+    const NdbTableImpl* bt = NULL;
+    const NdbColumnImpl* bc = NULL;
+    if (theStripeSize == 0 ||
+        (bt = theColumn->m_blobTable) == NULL ||
+        (bc = bt->getColumn("DATA")) == NULL ||
+        bc->getType() != partType ||
+        bc->getLength() != (int)thePartSize) {
+      setErrorCode(NdbBlobImpl::ErrTable);
+      DBUG_RETURN(-1);
+    }
+    // blob table
+    theBlobTable = &NdbTableImpl::getImpl(*bt);
+  }
+  // these buffers are always used
+  theKeyBuf.alloc(theTable->m_keyLenInWords << 2);
+  thePackKeyBuf.alloc(max(theTable->m_keyLenInWords, theAccessTable->m_keyLenInWords) << 2);
+  theHeadInlineBuf.alloc(sizeof(Head) + theInlineSize);
+  theHead = (Head*)theHeadInlineBuf.data;
+  theInlineData = theHeadInlineBuf.data + sizeof(Head);
+  thePartBuf.alloc(thePartSize);
+  DBUG_RETURN(0);
+}
+
 /*
  * Before execute of prepared operation.  May add new operations before
  * this one.  May ask that this operation and all before it (a "batch")
@@ -1264,7 +1590,7 @@ NdbBlob::preExecute(NdbTransaction::Exec
         DBUG_RETURN(-1);
       }
       if (isWriteOp()) {
-        tOp->m_abortOption = NdbTransaction::AO_IgnoreError;
+        tOp->m_abortOption = NdbOperation::AO_IgnoreError;
       }
       theHeadInlineReadOp = tOp;
       // execute immediately
@@ -1283,7 +1609,7 @@ NdbBlob::preExecute(NdbTransaction::Exec
         if (tOp == NULL ||
             tOp->readTuple() == -1 ||
             setAccessKeyValue(tOp) == -1 ||
-            tOp->getValue(pkAttrId, theKeyBuf.data) == NULL) {
+            tOp->getValue(pkAttrId, thePackKeyBuf.data) == NULL) {
           setErrorCode(tOp);
           DBUG_RETURN(-1);
         }
@@ -1310,7 +1636,7 @@ NdbBlob::preExecute(NdbTransaction::Exec
         DBUG_RETURN(-1);
       }
       if (isWriteOp()) {
-        tOp->m_abortOption = NdbTransaction::AO_IgnoreError;
+        tOp->m_abortOption = NdbOperation::AO_IgnoreError;
       }
       theHeadInlineReadOp = tOp;
       // execute immediately
@@ -1372,10 +1698,13 @@ NdbBlob::postExecute(NdbTransaction::Exe
   assert(isKeyOp());
   if (isIndexOp()) {
     NdbBlob* tFirstBlob = theNdbOp->theBlobList;
-    if (this != tFirstBlob) {
+    if (this == tFirstBlob) {
+      packKeyValue(theTable, theKeyBuf);
+    } else {
       // copy key from first blob
-      assert(theKeyBuf.size == tFirstBlob->theKeyBuf.size);
-      memcpy(theKeyBuf.data, tFirstBlob->theKeyBuf.data, tFirstBlob->theKeyBuf.size);
+      theKeyBuf.copyfrom(tFirstBlob->theKeyBuf);
+      thePackKeyBuf.copyfrom(tFirstBlob->thePackKeyBuf);
+      thePackKeyBuf.zerorest();
     }
   }
   if (isReadOp()) {
@@ -1480,7 +1809,7 @@ NdbBlob::postExecute(NdbTransaction::Exe
       setErrorCode(NdbBlobImpl::ErrAbort);
       DBUG_RETURN(-1);
     }
-    tOp->m_abortOption = NdbTransaction::AbortOnError;
+    tOp->m_abortOption = NdbOperation::AbortOnError;
     DBUG_PRINT("info", ("added op to update head+inline"));
   }
   DBUG_RETURN(0);
@@ -1510,7 +1839,7 @@ NdbBlob::preCommit()
           setErrorCode(NdbBlobImpl::ErrAbort);
           DBUG_RETURN(-1);
         }
-        tOp->m_abortOption = NdbTransaction::AbortOnError;
+        tOp->m_abortOption = NdbOperation::AbortOnError;
         DBUG_PRINT("info", ("added op to update head+inline"));
     }
   }
@@ -1529,12 +1858,17 @@ NdbBlob::atNextResult()
     DBUG_RETURN(-1);
   assert(isScanOp());
   // get primary key
-  { Uint32* data = (Uint32*)theKeyBuf.data;
-    unsigned size = theTable->m_keyLenInWords;
-    if (((NdbScanOperation*)theNdbOp)->getKeyFromKEYINFO20(data, size) == -1) {
+  { NdbScanOperation* tScanOp = (NdbScanOperation*)theNdbOp;
+    Uint32* data = (Uint32*)thePackKeyBuf.data;
+    unsigned size = theTable->m_keyLenInWords; // in-out
+    if (tScanOp->getKeyFromKEYINFO20(data, size) == -1) {
       setErrorCode(NdbBlobImpl::ErrUsage);
       DBUG_RETURN(-1);
     }
+    thePackKeyBuf.size = 4 * size;
+    thePackKeyBuf.zerorest();
+    if (unpackKeyValue(theTable, theKeyBuf) == -1)
+      DBUG_RETURN(-1);
   }
   getHeadFromRecAttr();
   if (setPos(0) == -1)
@@ -1554,6 +1888,30 @@ NdbBlob::atNextResult()
   DBUG_RETURN(0);
 }
 
+/*
+ * After next event on main table.
+ */
+int
+NdbBlob::atNextEvent()
+{
+  DBUG_ENTER("NdbBlob::atNextEvent");
+  Uint32 optype = 
+    SubTableData::getOperation(theEventOp->m_data_item->sdata->requestInfo);
+  DBUG_PRINT("info", ("this=%p op=%p blob op=%p version=%d optype=%u", this, theEventOp, theBlobEventOp, theEventBlobVersion, optype));
+  if (theState == Invalid)
+    DBUG_RETURN(-1);
+  assert(theEventBlobVersion >= 0);
+  if (optype >= NdbDictionary::Event::_TE_FIRST_NON_DATA_EVENT)
+    DBUG_RETURN(0);
+  getHeadFromRecAttr();
+  if (theNullFlag == -1) // value not defined
+    DBUG_RETURN(0);
+  if (setPos(0) == -1)
+    DBUG_RETURN(-1);
+  setState(Active);
+  DBUG_RETURN(0);
+}
+
 // misc
 
 const NdbDictionary::Column*
@@ -1600,6 +1958,17 @@ NdbBlob::setErrorCode(NdbTransaction* aC
   if (theNdbCon != NULL && (code = theNdbCon->theError.code) != 0)
     ;
   else if ((code = theNdb->theError.code) != 0)
+    ;
+  else
+    code = NdbBlobImpl::ErrUnknown;
+  setErrorCode(code, invalidFlag);
+}
+
+void
+NdbBlob::setErrorCode(NdbEventOperationImpl* anOp, bool invalidFlag)
+{
+  int code = 0;
+  if ((code = anOp->m_error.code) != 0)
     ;
   else
     code = NdbBlobImpl::ErrUnknown;
Thread
bk commit into 5.1 tree (knielsen:1.2482)knielsen12 Mar