NdbBlob.cpp
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:40k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2003 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. #include <Ndb.hpp>
  14. #include <NdbDictionaryImpl.hpp>
  15. #include <NdbConnection.hpp>
  16. #include <NdbOperation.hpp>
  17. #include <NdbIndexOperation.hpp>
  18. #include <NdbRecAttr.hpp>
  19. #include <NdbBlob.hpp>
  20. #include "NdbBlobImpl.hpp"
  21. #include <NdbScanOperation.hpp>
  22. #ifdef NDB_BLOB_DEBUG
  23. #define DBG(x) 
  24.   do { 
  25.     static const char* p = getenv("NDB_BLOB_DEBUG"); 
  26.     if (p == 0 || *p == 0 || *p == '0') break; 
  27.     static char* prefix = "BLOB"; 
  28.     const char* cname = theColumn == NULL ? "-" : theColumn->m_name.c_str(); 
  29.     ndbout << prefix << " " << hex << (void*)this << " " << cname; 
  30.     ndbout << " " << dec << __LINE__ << " " << x << " " << *this << endl; 
  31.   } while (0)
  32. static char*
  33. ndb_blob_debug(const Uint32* data, unsigned size)
  34. {
  35.   static char buf[200]; // MT irrelevant
  36.   buf[0] = 0;
  37.   for (unsigned i = 0; i < size; i++) {
  38.     unsigned n = strlen(buf);
  39.     if (n + 10 < sizeof(buf))
  40.       sprintf(buf + n, "%*s%08x", i != 0, "", data[i]);
  41.   }
  42.   return buf;
  43. }
  44. #else
  45. #define DBG(x)
  46. #endif
  47. /*
  48.  * Reading index table directly (as a table) is faster but there are
  49.  * bugs or limitations.  Keep the code and make possible to choose.
  50.  */
  51. static const bool g_ndb_blob_ok_to_read_index_table = false;
  52. // state (inline)
  53. inline void
  54. NdbBlob::setState(State newState)
  55. {
  56.   DBG("setState " << newState);
  57.   theState = newState;
  58. }
  59. // define blob table
  60. int
  61. NdbBlob::getBlobTableName(char* btname, Ndb* anNdb, const char* tableName, const char* columnName)
  62. {
  63.   NdbTableImpl* t = anNdb->theDictionary->m_impl.getTable(tableName);
  64.   if (t == NULL)
  65.     return -1;
  66.   NdbColumnImpl* c = t->getColumn(columnName);
  67.   if (c == NULL)
  68.     return -1;
  69.   getBlobTableName(btname, t, c);
  70.   return 0;
  71. }
  72. void
  73. NdbBlob::getBlobTableName(char* btname, const NdbTableImpl* t, const NdbColumnImpl* c)
  74. {
  75.   assert(t != 0 && c != 0 && c->getBlobType());
  76.   memset(btname, 0, NdbBlobImpl::BlobTableNameSize);
  77.   sprintf(btname, "NDB$BLOB_%d_%d", (int)t->m_tableId, (int)c->m_attrId);
  78. }
  79. void
  80. NdbBlob::getBlobTable(NdbTableImpl& bt, const NdbTableImpl* t, const NdbColumnImpl* c)
  81. {
  82.   char btname[NdbBlobImpl::BlobTableNameSize];
  83.   getBlobTableName(btname, t, c);
  84.   bt.setName(btname);
  85.   bt.setLogging(t->getLogging());
  86.   bt.setFragmentType(t->getFragmentType());
  87.   { NdbDictionary::Column bc("PK");
  88.     bc.setType(NdbDictionary::Column::Unsigned);
  89.     assert(t->m_sizeOfKeysInWords != 0);
  90.     bc.setLength(t->m_sizeOfKeysInWords);
  91.     bc.setPrimaryKey(true);
  92.     bc.setDistributionKey(true);
  93.     bt.addColumn(bc);
  94.   }
  95.   { NdbDictionary::Column bc("DIST");
  96.     bc.setType(NdbDictionary::Column::Unsigned);
  97.     bc.setPrimaryKey(true);
  98.     bc.setDistributionKey(true);
  99.     bt.addColumn(bc);
  100.   }
  101.   { NdbDictionary::Column bc("PART");
  102.     bc.setType(NdbDictionary::Column::Unsigned);
  103.     bc.setPrimaryKey(true);
  104.     bc.setDistributionKey(false);
  105.     bt.addColumn(bc);
  106.   }
  107.   { NdbDictionary::Column bc("DATA");
  108.     switch (c->m_type) {
  109.     case NdbDictionary::Column::Blob:
  110.       bc.setType(NdbDictionary::Column::Binary);
  111.       break;
  112.     case NdbDictionary::Column::Text:
  113.       bc.setType(NdbDictionary::Column::Char);
  114.       break;
  115.     default:
  116.       assert(false);
  117.       break;
  118.     }
  119.     bc.setLength(c->getPartSize());
  120.     bt.addColumn(bc);
  121.   }
  122. }
  123. // initialization
  124. NdbBlob::NdbBlob(Ndb*)
  125. {
  126.   init();
  127. }
  128. void
  129. NdbBlob::init()
  130. {
  131.   theState = Idle;
  132.   theNdb = NULL;
  133.   theNdbCon = NULL;
  134.   theNdbOp = NULL;
  135.   theTable = NULL;
  136.   theAccessTable = NULL;
  137.   theBlobTable = NULL;
  138.   theColumn = NULL;
  139.   theFillChar = 0;
  140.   theInlineSize = 0;
  141.   thePartSize = 0;
  142.   theStripeSize = 0;
  143.   theGetFlag = false;
  144.   theGetBuf = NULL;
  145.   theSetFlag = false;
  146.   theSetBuf = NULL;
  147.   theGetSetBytes = 0;
  148.   thePendingBlobOps = 0;
  149.   theActiveHook = NULL;
  150.   theActiveHookArg = NULL;
  151.   theHead = NULL;
  152.   theInlineData = NULL;
  153.   theHeadInlineRecAttr = NULL;
  154.   theHeadInlineReadOp = NULL;
  155.   theHeadInlineUpdateFlag = false;
  156.   theNullFlag = -1;
  157.   theLength = 0;
  158.   thePos = 0;
  159.   theNext = NULL;
  160. }
  161. void
  162. NdbBlob::release()
  163. {
  164.   setState(Idle);
  165. }
  166. // buffers
  167. NdbBlob::Buf::Buf() :
  168.   data(NULL),
  169.   size(0),
  170.   maxsize(0)
  171. {
  172. }
  173. NdbBlob::Buf::~Buf()
  174. {
  175.   delete [] data;
  176. }
  177. void
  178. NdbBlob::Buf::alloc(unsigned n)
  179. {
  180.   size = n;
  181.   if (maxsize < n) {
  182.     delete [] data;
  183.     // align to Uint64
  184.     if (n % 8 != 0)
  185.       n += 8 - n % 8;
  186.     data = new char [n];
  187.     maxsize = n;
  188.   }
  189. #ifdef VM_TRACE
  190.   memset(data, 'X', maxsize);
  191. #endif
  192. }
  193. void
  194. NdbBlob::Buf::copyfrom(const NdbBlob::Buf& src)
  195. {
  196.   assert(size == src.size);
  197.   memcpy(data, src.data, size);
  198. }
  199. // classify operations (inline)
  200. inline bool
  201. NdbBlob::isTableOp()
  202. {
  203.   return theTable == theAccessTable;
  204. }
  205. inline bool
  206. NdbBlob::isIndexOp()
  207. {
  208.   return theTable != theAccessTable;
  209. }
  210. inline bool
  211. NdbBlob::isKeyOp()
  212. {
  213.   return
  214.     theNdbOp->theOperationType == NdbOperation::InsertRequest ||
  215.     theNdbOp->theOperationType == NdbOperation::UpdateRequest ||
  216.     theNdbOp->theOperationType == NdbOperation::WriteRequest ||
  217.     theNdbOp->theOperationType == NdbOperation::ReadRequest ||
  218.     theNdbOp->theOperationType == NdbOperation::ReadExclusive ||
  219.     theNdbOp->theOperationType == NdbOperation::DeleteRequest;
  220. }
  221. inline bool
  222. NdbBlob::isReadOp()
  223. {
  224.   return
  225.     theNdbOp->theOperationType == NdbOperation::ReadRequest ||
  226.     theNdbOp->theOperationType == NdbOperation::ReadExclusive;
  227. }
  228. inline bool
  229. NdbBlob::isInsertOp()
  230. {
  231.   return
  232.     theNdbOp->theOperationType == NdbOperation::InsertRequest;
  233. }
  234. inline bool
  235. NdbBlob::isUpdateOp()
  236. {
  237.   return
  238.     theNdbOp->theOperationType == NdbOperation::UpdateRequest;
  239. }
  240. inline bool
  241. NdbBlob::isWriteOp()
  242. {
  243.   return
  244.     theNdbOp->theOperationType == NdbOperation::WriteRequest;
  245. }
  246. inline bool
  247. NdbBlob::isDeleteOp()
  248. {
  249.   return
  250.     theNdbOp->theOperationType == NdbOperation::DeleteRequest;
  251. }
  252. inline bool
  253. NdbBlob::isScanOp()
  254. {
  255.   return
  256.     theNdbOp->theOperationType == NdbOperation::OpenScanRequest ||
  257.     theNdbOp->theOperationType == NdbOperation::OpenRangeScanRequest;
  258. }
  259. // computations (inline)
  260. inline Uint32
  261. NdbBlob::getPartNumber(Uint64 pos)
  262. {
  263.   assert(thePartSize != 0 && pos >= theInlineSize);
  264.   return (pos - theInlineSize) / thePartSize;
  265. }
  266. inline Uint32
  267. NdbBlob::getPartCount()
  268. {
  269.   if (theLength <= theInlineSize)
  270.     return 0;
  271.   return 1 + getPartNumber(theLength - 1);
  272. }
  273. inline Uint32
  274. NdbBlob::getDistKey(Uint32 part)
  275. {
  276.   assert(theStripeSize != 0);
  277.   return (part / theStripeSize) % theStripeSize;
  278. }
  279. // getters and setters
  280. int
  281. NdbBlob::getTableKeyValue(NdbOperation* anOp)
  282. {
  283.   Uint32* data = (Uint32*)theKeyBuf.data;
  284.   unsigned pos = 0;
  285.   DBG("getTableKeyValue");
  286.   for (unsigned i = 0; i < theTable->m_columns.size(); i++) {
  287.     NdbColumnImpl* c = theTable->m_columns[i];
  288.     assert(c != NULL);
  289.     if (c->m_pk) {
  290.       unsigned len = c->m_attrSize * c->m_arraySize;
  291.       if (anOp->getValue_impl(c, (char*)&data[pos]) == NULL) {
  292.         setErrorCode(anOp);
  293.         return -1;
  294.       }
  295.       // odd bytes receive no data and must be zeroed
  296.       while (len % 4 != 0) {
  297.         char* p = (char*)&data[pos] + len++;
  298.         *p = 0;
  299.       }
  300.       pos += len / 4;
  301.     }
  302.   }
  303.   assert(pos == theKeyBuf.size / 4);
  304.   return 0;
  305. }
  306. int
  307. NdbBlob::setTableKeyValue(NdbOperation* anOp)
  308. {
  309.   const Uint32* data = (const Uint32*)theKeyBuf.data;
  310.   DBG("setTableKeyValue key=" << ndb_blob_debug(data, theTable->m_sizeOfKeysInWords));
  311.   const unsigned columns = theTable->m_columns.size();
  312.   unsigned pos = 0;
  313.   for (unsigned i = 0; i < columns; i++) {
  314.     NdbColumnImpl* c = theTable->m_columns[i];
  315.     assert(c != NULL);
  316.     if (c->m_pk) {
  317.       unsigned len = c->m_attrSize * c->m_arraySize;
  318.       if (anOp->equal_impl(c, (const char*)&data[pos], len) == -1) {
  319.         setErrorCode(anOp);
  320.         return -1;
  321.       }
  322.       pos += (len + 3) / 4;
  323.     }
  324.   }
  325.   assert(pos == theKeyBuf.size / 4);
  326.   return 0;
  327. }
  328. int
  329. NdbBlob::setAccessKeyValue(NdbOperation* anOp)
  330. {
  331.   const Uint32* data = (const Uint32*)theAccessKeyBuf.data;
  332.   DBG("setAccessKeyValue key=" << ndb_blob_debug(data, theAccessTable->m_sizeOfKeysInWords));
  333.   const unsigned columns = theAccessTable->m_columns.size();
  334.   unsigned pos = 0;
  335.   for (unsigned i = 0; i < columns; i++) {
  336.     NdbColumnImpl* c = theAccessTable->m_columns[i];
  337.     assert(c != NULL);
  338.     if (c->m_pk) {
  339.       unsigned len = c->m_attrSize * c->m_arraySize;
  340.       if (anOp->equal_impl(c, (const char*)&data[pos], len) == -1) {
  341.         setErrorCode(anOp);
  342.         return -1;
  343.       }
  344.       pos += (len + 3) / 4;
  345.     }
  346.   }
  347.   assert(pos == theAccessKeyBuf.size / 4);
  348.   return 0;
  349. }
  350. int
  351. NdbBlob::setPartKeyValue(NdbOperation* anOp, Uint32 part)
  352. {
  353.   Uint32* data = (Uint32*)theKeyBuf.data;
  354.   unsigned size = theTable->m_sizeOfKeysInWords;
  355.   DBG("setPartKeyValue dist=" << getDistKey(part) << " part=" << part << " key=" << ndb_blob_debug(data, size));
  356.   // TODO use attr ids after compatibility with 4.1.7 not needed
  357.   if (anOp->equal("PK", theKeyBuf.data) == -1 ||
  358.       anOp->equal("DIST", getDistKey(part)) == -1 ||
  359.       anOp->equal("PART", part) == -1) {
  360.     setErrorCode(anOp);
  361.     return -1;
  362.   }
  363.   return 0;
  364. }
  365. int
  366. NdbBlob::getHeadInlineValue(NdbOperation* anOp)
  367. {
  368.   DBG("getHeadInlineValue");
  369.   theHeadInlineRecAttr = anOp->getValue_impl(theColumn, theHeadInlineBuf.data);
  370.   if (theHeadInlineRecAttr == NULL) {
  371.     setErrorCode(anOp);
  372.     return -1;
  373.   }
  374.   return 0;
  375. }
  376. void
  377. NdbBlob::getHeadFromRecAttr()
  378. {
  379.   assert(theHeadInlineRecAttr != NULL);
  380.   theNullFlag = theHeadInlineRecAttr->isNULL();
  381.   assert(theNullFlag != -1);
  382.   theLength = ! theNullFlag ? theHead->length : 0;
  383.   DBG("getHeadFromRecAttr [out]");
  384. }
  385. int
  386. NdbBlob::setHeadInlineValue(NdbOperation* anOp)
  387. {
  388.   DBG("setHeadInlineValue");
  389.   theHead->length = theLength;
  390.   if (theLength < theInlineSize)
  391.     memset(theInlineData + theLength, 0, theInlineSize - theLength);
  392.   assert(theNullFlag != -1);
  393.   const char* aValue = theNullFlag ? 0 : theHeadInlineBuf.data;
  394.   if (anOp->setValue(theColumn, aValue, theHeadInlineBuf.size) == -1) {
  395.     setErrorCode(anOp);
  396.     return -1;
  397.   }
  398.   theHeadInlineUpdateFlag = false;
  399.   return 0;
  400. }
  401. // getValue/setValue
  402. int
  403. NdbBlob::getValue(void* data, Uint32 bytes)
  404. {
  405.   DBG("getValue data=" << hex << data << " bytes=" << dec << bytes);
  406.   if (theGetFlag || theState != Prepared) {
  407.     setErrorCode(NdbBlobImpl::ErrState);
  408.     return -1;
  409.   }
  410.   if (! isReadOp() && ! isScanOp()) {
  411.     setErrorCode(NdbBlobImpl::ErrUsage);
  412.     return -1;
  413.   }
  414.   if (data == NULL && bytes != 0) {
  415.     setErrorCode(NdbBlobImpl::ErrUsage);
  416.     return -1;
  417.   }
  418.   theGetFlag = true;
  419.   theGetBuf = static_cast<char*>(data);
  420.   theGetSetBytes = bytes;
  421.   return 0;
  422. }
  423. int
  424. NdbBlob::setValue(const void* data, Uint32 bytes)
  425. {
  426.   DBG("setValue data=" << hex << data << " bytes=" << dec << bytes);
  427.   if (theSetFlag || theState != Prepared) {
  428.     setErrorCode(NdbBlobImpl::ErrState);
  429.     return -1;
  430.   }
  431.   if (! isInsertOp() && ! isUpdateOp() && ! isWriteOp()) {
  432.     setErrorCode(NdbBlobImpl::ErrUsage);
  433.     return -1;
  434.   }
  435.   if (data == NULL && bytes != 0) {
  436.     setErrorCode(NdbBlobImpl::ErrUsage);
  437.     return -1;
  438.   }
  439.   theSetFlag = true;
  440.   theSetBuf = static_cast<const char*>(data);
  441.   theGetSetBytes = bytes;
  442.   if (isInsertOp()) {
  443.     // write inline part now
  444.     if (theSetBuf != NULL) {
  445.       Uint32 n = theGetSetBytes;
  446.       if (n > theInlineSize)
  447.         n = theInlineSize;
  448.       assert(thePos == 0);
  449.       if (writeDataPrivate(theSetBuf, n) == -1)
  450.         return -1;
  451.     } else {
  452.       theNullFlag = true;
  453.       theLength = 0;
  454.     }
  455.     if (setHeadInlineValue(theNdbOp) == -1)
  456.       return -1;
  457.   }
  458.   return 0;
  459. }
  460. // activation hook
  461. int
  462. NdbBlob::setActiveHook(ActiveHook activeHook, void* arg)
  463. {
  464.   DBG("setActiveHook hook=" << hex << (void*)activeHook << " arg=" << hex << arg);
  465.   if (theState != Prepared) {
  466.     setErrorCode(NdbBlobImpl::ErrState);
  467.     return -1;
  468.   }
  469.   theActiveHook = activeHook;
  470.   theActiveHookArg = arg;
  471.   return 0;
  472. }
  473. // misc operations
  474. int
  475. NdbBlob::getNull(bool& isNull)
  476. {
  477.   DBG("getNull");
  478.   if (theState == Prepared && theSetFlag) {
  479.     isNull = (theSetBuf == NULL);
  480.     return 0;
  481.   }
  482.   if (theNullFlag == -1) {
  483.     setErrorCode(NdbBlobImpl::ErrState);
  484.     return -1;
  485.   }
  486.   isNull = theNullFlag;
  487.   return 0;
  488. }
  489. int
  490. NdbBlob::setNull()
  491. {
  492.   DBG("setNull");
  493.   if (theNullFlag == -1) {
  494.     if (theState == Prepared) {
  495.       return setValue(0, 0);
  496.     }
  497.     setErrorCode(NdbBlobImpl::ErrState);
  498.     return -1;
  499.   }
  500.   if (theNullFlag)
  501.     return 0;
  502.   if (deleteParts(0, getPartCount()) == -1)
  503.     return -1;
  504.   theNullFlag = true;
  505.   theLength = 0;
  506.   theHeadInlineUpdateFlag = true;
  507.   return 0;
  508. }
  509. int
  510. NdbBlob::getLength(Uint64& len)
  511. {
  512.   DBG("getLength");
  513.   if (theState == Prepared && theSetFlag) {
  514.     len = theGetSetBytes;
  515.     return 0;
  516.   }
  517.   if (theNullFlag == -1) {
  518.     setErrorCode(NdbBlobImpl::ErrState);
  519.     return -1;
  520.   }
  521.   len = theLength;
  522.   return 0;
  523. }
  524. int
  525. NdbBlob::truncate(Uint64 length)
  526. {
  527.   DBG("truncate [in] length=" << length);
  528.   if (theNullFlag == -1) {
  529.     setErrorCode(NdbBlobImpl::ErrState);
  530.     return -1;
  531.   }
  532.   if (theLength > length) {
  533.     if (length > theInlineSize) {
  534.       Uint32 part1 = getPartNumber(length - 1);
  535.       Uint32 part2 = getPartNumber(theLength - 1);
  536.       assert(part2 >= part1);
  537.       if (part2 > part1 && deleteParts(part1 + 1, part2 - part1) == -1)
  538.         return -1;
  539.     } else {
  540.       if (deleteParts(0, getPartCount()) == -1)
  541.         return -1;
  542.     }
  543.     theLength = length;
  544.     theHeadInlineUpdateFlag = true;
  545.     if (thePos > length)
  546.       thePos = length;
  547.   }
  548.   DBG("truncate [out]");
  549.   return 0;
  550. }
  551. int
  552. NdbBlob::getPos(Uint64& pos)
  553. {
  554.   DBG("getPos");
  555.   if (theNullFlag == -1) {
  556.     setErrorCode(NdbBlobImpl::ErrState);
  557.     return -1;
  558.   }
  559.   pos = thePos;
  560.   return 0;
  561. }
  562. int
  563. NdbBlob::setPos(Uint64 pos)
  564. {
  565.   DBG("setPos pos=" << pos);
  566.   if (theNullFlag == -1) {
  567.     setErrorCode(NdbBlobImpl::ErrState);
  568.     return -1;
  569.   }
  570.   if (pos > theLength) {
  571.     setErrorCode(NdbBlobImpl::ErrSeek);
  572.     return -1;
  573.   }
  574.   thePos = pos;
  575.   return 0;
  576. }
  577. // read/write
  578. int
  579. NdbBlob::readData(void* data, Uint32& bytes)
  580. {
  581.   if (theState != Active) {
  582.     setErrorCode(NdbBlobImpl::ErrState);
  583.     return -1;
  584.   }
  585.   char* buf = static_cast<char*>(data);
  586.   return readDataPrivate(buf, bytes);
  587. }
  588. int
  589. NdbBlob::readDataPrivate(char* buf, Uint32& bytes)
  590. {
  591.   DBG("readData [in] bytes=" << bytes);
  592.   assert(thePos <= theLength);
  593.   Uint64 pos = thePos;
  594.   if (bytes > theLength - pos)
  595.     bytes = theLength - pos;
  596.   Uint32 len = bytes;
  597.   if (len > 0) {
  598.     // inline part
  599.     if (pos < theInlineSize) {
  600.       Uint32 n = theInlineSize - pos;
  601.       if (n > len)
  602.         n = len;
  603.       memcpy(buf, theInlineData + pos, n);
  604.       pos += n;
  605.       buf += n;
  606.       len -= n;
  607.     }
  608.   }
  609.   if (len > 0 && thePartSize == 0) {
  610.     setErrorCode(NdbBlobImpl::ErrSeek);
  611.     return -1;
  612.   }
  613.   if (len > 0) {
  614.     assert(pos >= theInlineSize);
  615.     Uint32 off = (pos - theInlineSize) % thePartSize;
  616.     // partial first block
  617.     if (off != 0) {
  618.       DBG("partial first block pos=" << pos << " len=" << len);
  619.       Uint32 part = (pos - theInlineSize) / thePartSize;
  620.       if (readParts(thePartBuf.data, part, 1) == -1)
  621.         return -1;
  622.       // need result now
  623.       if (executePendingBlobReads() == -1)
  624.         return -1;
  625.       Uint32 n = thePartSize - off;
  626.       if (n > len)
  627.         n = len;
  628.       memcpy(buf, thePartBuf.data + off, n);
  629.       pos += n;
  630.       buf += n;
  631.       len -= n;
  632.     }
  633.   }
  634.   if (len > 0) {
  635.     assert((pos - theInlineSize) % thePartSize == 0);
  636.     // complete blocks in the middle
  637.     if (len >= thePartSize) {
  638.       Uint32 part = (pos - theInlineSize) / thePartSize;
  639.       Uint32 count = len / thePartSize;
  640.       if (readParts(buf, part, count) == -1)
  641.         return -1;
  642.       Uint32 n = thePartSize * count;
  643.       pos += n;
  644.       buf += n;
  645.       len -= n;
  646.     }
  647.   }
  648.   if (len > 0) {
  649.     // partial last block
  650.     DBG("partial last block pos=" << pos << " len=" << len);
  651.     assert((pos - theInlineSize) % thePartSize == 0 && len < thePartSize);
  652.     Uint32 part = (pos - theInlineSize) / thePartSize;
  653.     if (readParts(thePartBuf.data, part, 1) == -1)
  654.       return -1;
  655.     // need result now
  656.     if (executePendingBlobReads() == -1)
  657.       return -1;
  658.     memcpy(buf, thePartBuf.data, len);
  659.     Uint32 n = len;
  660.     pos += n;
  661.     buf += n;
  662.     len -= n;
  663.   }
  664.   assert(len == 0);
  665.   thePos = pos;
  666.   assert(thePos <= theLength);
  667.   DBG("readData [out]");
  668.   return 0;
  669. }
  670. int
  671. NdbBlob::writeData(const void* data, Uint32 bytes)
  672. {
  673.   if (theState != Active) {
  674.     setErrorCode(NdbBlobImpl::ErrState);
  675.     return -1;
  676.   }
  677.   const char* buf = static_cast<const char*>(data);
  678.   return writeDataPrivate(buf, bytes);
  679. }
  680. int
  681. NdbBlob::writeDataPrivate(const char* buf, Uint32 bytes)
  682. {
  683.   DBG("writeData [in] bytes=" << bytes);
  684.   assert(thePos <= theLength);
  685.   Uint64 pos = thePos;
  686.   Uint32 len = bytes;
  687.   // any write makes blob not NULL
  688.   if (theNullFlag) {
  689.     theNullFlag = false;
  690.     theHeadInlineUpdateFlag = true;
  691.   }
  692.   if (len > 0) {
  693.     // inline part
  694.     if (pos < theInlineSize) {
  695.       Uint32 n = theInlineSize - pos;
  696.       if (n > len)
  697.         n = len;
  698.       memcpy(theInlineData + pos, buf, n);
  699.       theHeadInlineUpdateFlag = true;
  700.       pos += n;
  701.       buf += n;
  702.       len -= n;
  703.     }
  704.   }
  705.   if (len > 0 && thePartSize == 0) {
  706.     setErrorCode(NdbBlobImpl::ErrSeek);
  707.     return -1;
  708.   }
  709.   if (len > 0) {
  710.     assert(pos >= theInlineSize);
  711.     Uint32 off = (pos - theInlineSize) % thePartSize;
  712.     // partial first block
  713.     if (off != 0) {
  714.       DBG("partial first block pos=" << pos << " len=" << len);
  715.       // flush writes to guarantee correct read
  716.       if (executePendingBlobWrites() == -1)
  717.         return -1;
  718.       Uint32 part = (pos - theInlineSize) / thePartSize;
  719.       if (readParts(thePartBuf.data, part, 1) == -1)
  720.         return -1;
  721.       // need result now
  722.       if (executePendingBlobReads() == -1)
  723.         return -1;
  724.       Uint32 n = thePartSize - off;
  725.       if (n > len) {
  726.         memset(thePartBuf.data + off + len, theFillChar, n - len);
  727.         n = len;
  728.       }
  729.       memcpy(thePartBuf.data + off, buf, n);
  730.       if (updateParts(thePartBuf.data, part, 1) == -1)
  731.         return -1;
  732.       pos += n;
  733.       buf += n;
  734.       len -= n;
  735.     }
  736.   }
  737.   if (len > 0) {
  738.     assert((pos - theInlineSize) % thePartSize == 0);
  739.     // complete blocks in the middle
  740.     if (len >= thePartSize) {
  741.       Uint32 part = (pos - theInlineSize) / thePartSize;
  742.       Uint32 count = len / thePartSize;
  743.       for (unsigned i = 0; i < count; i++) {
  744.         if (part + i < getPartCount()) {
  745.           if (updateParts(buf, part + i, 1) == -1)
  746.             return -1;
  747.         } else {
  748.           if (insertParts(buf, part + i, 1) == -1)
  749.             return -1;
  750.         }
  751.         Uint32 n = thePartSize;
  752.         pos += n;
  753.         buf += n;
  754.         len -= n;
  755.       }
  756.     }
  757.   }
  758.   if (len > 0) {
  759.     // partial last block
  760.     DBG("partial last block pos=" << pos << " len=" << len);
  761.     assert((pos - theInlineSize) % thePartSize == 0 && len < thePartSize);
  762.     Uint32 part = (pos - theInlineSize) / thePartSize;
  763.     if (theLength > pos + len) {
  764.       // flush writes to guarantee correct read
  765.       if (executePendingBlobWrites() == -1)
  766.         return -1;
  767.       if (readParts(thePartBuf.data, part, 1) == -1)
  768.         return -1;
  769.       // need result now
  770.       if (executePendingBlobReads() == -1)
  771.         return -1;
  772.       memcpy(thePartBuf.data, buf, len);
  773.       if (updateParts(thePartBuf.data, part, 1) == -1)
  774.         return -1;
  775.     } else {
  776.       memcpy(thePartBuf.data, buf, len);
  777.       memset(thePartBuf.data + len, theFillChar, thePartSize - len);
  778.       if (part < getPartCount()) {
  779.         if (updateParts(thePartBuf.data, part, 1) == -1)
  780.           return -1;
  781.       } else {
  782.         if (insertParts(thePartBuf.data, part, 1) == -1)
  783.           return -1;
  784.       }
  785.     }
  786.     Uint32 n = len;
  787.     pos += n;
  788.     buf += n;
  789.     len -= n;
  790.   }
  791.   assert(len == 0);
  792.   if (theLength < pos) {
  793.     theLength = pos;
  794.     theHeadInlineUpdateFlag = true;
  795.   }
  796.   thePos = pos;
  797.   assert(thePos <= theLength);
  798.   DBG("writeData [out]");
  799.   return 0;
  800. }
  801. int
  802. NdbBlob::readParts(char* buf, Uint32 part, Uint32 count)
  803. {
  804.   DBG("readParts [in] part=" << part << " count=" << count);
  805.   Uint32 n = 0;
  806.   while (n < count) {
  807.     NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable);
  808.     if (tOp == NULL ||
  809.         tOp->committedRead() == -1 ||
  810.         setPartKeyValue(tOp, part + n) == -1 ||
  811.         tOp->getValue((Uint32)3, buf) == NULL) {
  812.       setErrorCode(tOp);
  813.       return -1;
  814.     }
  815.     tOp->m_abortOption = AbortOnError;
  816.     buf += thePartSize;
  817.     n++;
  818.     thePendingBlobOps |= (1 << NdbOperation::ReadRequest);
  819.     theNdbCon->thePendingBlobOps |= (1 << NdbOperation::ReadRequest);
  820.   }
  821.   return 0;
  822. }
  823. int
  824. NdbBlob::insertParts(const char* buf, Uint32 part, Uint32 count)
  825. {
  826.   DBG("insertParts [in] part=" << part << " count=" << count);
  827.   Uint32 n = 0;
  828.   while (n < count) {
  829.     NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable);
  830.     if (tOp == NULL ||
  831.         tOp->insertTuple() == -1 ||
  832.         setPartKeyValue(tOp, part + n) == -1 ||
  833.         tOp->setValue((Uint32)3, buf) == -1) {
  834.       setErrorCode(tOp);
  835.       return -1;
  836.     }
  837.     tOp->m_abortOption = AbortOnError;
  838.     buf += thePartSize;
  839.     n++;
  840.     thePendingBlobOps |= (1 << NdbOperation::InsertRequest);
  841.     theNdbCon->thePendingBlobOps |= (1 << NdbOperation::InsertRequest);
  842.   }
  843.   return 0;
  844. }
  845. int
  846. NdbBlob::updateParts(const char* buf, Uint32 part, Uint32 count)
  847. {
  848.   DBG("updateParts [in] part=" << part << " count=" << count);
  849.   Uint32 n = 0;
  850.   while (n < count) {
  851.     NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable);
  852.     if (tOp == NULL ||
  853.         tOp->updateTuple() == -1 ||
  854.         setPartKeyValue(tOp, part + n) == -1 ||
  855.         tOp->setValue((Uint32)3, buf) == -1) {
  856.       setErrorCode(tOp);
  857.       return -1;
  858.     }
  859.     tOp->m_abortOption = AbortOnError;
  860.     buf += thePartSize;
  861.     n++;
  862.     thePendingBlobOps |= (1 << NdbOperation::UpdateRequest);
  863.     theNdbCon->thePendingBlobOps |= (1 << NdbOperation::UpdateRequest);
  864.   }
  865.   return 0;
  866. }
  867. int
  868. NdbBlob::deleteParts(Uint32 part, Uint32 count)
  869. {
  870.   DBG("deleteParts [in] part=" << part << " count=" << count);
  871.   Uint32 n = 0;
  872.   while (n < count) {
  873.     NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable);
  874.     if (tOp == NULL ||
  875.         tOp->deleteTuple() == -1 ||
  876.         setPartKeyValue(tOp, part + n) == -1) {
  877.       setErrorCode(tOp);
  878.       return -1;
  879.     }
  880.     tOp->m_abortOption = AbortOnError;
  881.     n++;
  882.     thePendingBlobOps |= (1 << NdbOperation::DeleteRequest);
  883.     theNdbCon->thePendingBlobOps |= (1 << NdbOperation::DeleteRequest);
  884.   }
  885.   return 0;
  886. }
  887. /*
  888.  * Number of blob parts not known.  Used to check for race condition
  889.  * when writeTuple is used for insert.  Deletes all parts found.
  890.  */
  891. int
  892. NdbBlob::deletePartsUnknown(Uint32 part)
  893. {
  894.   DBG("deletePartsUnknown [in] part=" << part << " count=all");
  895.   static const unsigned maxbat = 256;
  896.   static const unsigned minbat = 1;
  897.   unsigned bat = minbat;
  898.   NdbOperation* tOpList[maxbat];
  899.   Uint32 count = 0;
  900.   while (true) {
  901.     Uint32 n;
  902.     n = 0;
  903.     while (n < bat) {
  904.       NdbOperation*& tOp = tOpList[n];  // ref
  905.       tOp = theNdbCon->getNdbOperation(theBlobTable);
  906.       if (tOp == NULL ||
  907.           tOp->deleteTuple() == -1 ||
  908.           setPartKeyValue(tOp, part + count + n) == -1) {
  909.         setErrorCode(tOp);
  910.         return -1;
  911.       }
  912.       tOp->m_abortOption = AO_IgnoreError;
  913.       n++;
  914.     }
  915.     DBG("deletePartsUnknown: executeNoBlobs [in] bat=" << bat);
  916.     if (theNdbCon->executeNoBlobs(NoCommit) == -1)
  917.       return -1;
  918.     DBG("deletePartsUnknown: executeNoBlobs [out]");
  919.     n = 0;
  920.     while (n < bat) {
  921.       NdbOperation* tOp = tOpList[n];
  922.       if (tOp->theError.code != 0) {
  923.         if (tOp->theError.code != 626) {
  924.           setErrorCode(tOp);
  925.           return -1;
  926.         }
  927.         // first non-existent part
  928.         DBG("deletePartsUnknown [out] count=" << count);
  929.         return 0;
  930.       }
  931.       n++;
  932.       count++;
  933.     }
  934.     bat *= 4;
  935.     if (bat > maxbat)
  936.       bat = maxbat;
  937.   }
  938. }
  939. // pending ops
  940. int
  941. NdbBlob::executePendingBlobReads()
  942. {
  943.   Uint8 flags = (1 << NdbOperation::ReadRequest);
  944.   if (thePendingBlobOps & flags) {
  945.     DBG("executePendingBlobReads: executeNoBlobs [in]");
  946.     if (theNdbCon->executeNoBlobs(NoCommit) == -1)
  947.       return -1;
  948.     DBG("executePendingBlobReads: executeNoBlobs [out]");
  949.     thePendingBlobOps = 0;
  950.     theNdbCon->thePendingBlobOps = 0;
  951.   }
  952.   return 0;
  953. }
  954. int
  955. NdbBlob::executePendingBlobWrites()
  956. {
  957.   Uint8 flags = 0xFF & ~(1 << NdbOperation::ReadRequest);
  958.   if (thePendingBlobOps & flags) {
  959.     DBG("executePendingBlobWrites: executeNoBlobs [in]");
  960.     if (theNdbCon->executeNoBlobs(NoCommit) == -1)
  961.       return -1;
  962.     DBG("executePendingBlobWrites: executeNoBlobs [out]");
  963.     thePendingBlobOps = 0;
  964.     theNdbCon->thePendingBlobOps = 0;
  965.   }
  966.   return 0;
  967. }
  968. // callbacks
  969. int
  970. NdbBlob::invokeActiveHook()
  971. {
  972.   DBG("invokeActiveHook [in]");
  973.   assert(theState == Active && theActiveHook != NULL);
  974.   int ret = (*theActiveHook)(this, theActiveHookArg);
  975.   DBG("invokeActiveHook [out] ret=" << ret);
  976.   if (ret != 0) {
  977.     // no error is set on blob level
  978.     return -1;
  979.   }
  980.   return 0;
  981. }
  982. // blob handle maintenance
  983. /*
  984.  * Prepare blob handle linked to an operation.  Checks blob table.
  985.  * Allocates buffers.  For key operation fetches key data from signal
  986.  * data.  For read operation adds read of head+inline.
  987.  */
  988. int
  989. NdbBlob::atPrepare(NdbConnection* aCon, NdbOperation* anOp, const NdbColumnImpl* aColumn)
  990. {
  991.   assert(theState == Idle);
  992.   // ndb api stuff
  993.   theNdb = anOp->theNdb;
  994.   theNdbCon = aCon;     // for scan, this is the real transaction (m_transConnection)
  995.   theNdbOp = anOp;
  996.   theTable = anOp->m_currentTable;
  997.   theAccessTable = anOp->m_accessTable;
  998.   theColumn = aColumn;
  999.   DBG("atPrepare [in]");
  1000.   NdbDictionary::Column::Type partType = NdbDictionary::Column::Undefined;
  1001.   switch (theColumn->getType()) {
  1002.   case NdbDictionary::Column::Blob:
  1003.     partType = NdbDictionary::Column::Binary;
  1004.     theFillChar = 0x0;
  1005.     break;
  1006.   case NdbDictionary::Column::Text:
  1007.     partType = NdbDictionary::Column::Char;
  1008.     theFillChar = 0x20;
  1009.     break;
  1010.   default:
  1011.     setErrorCode(NdbBlobImpl::ErrUsage);
  1012.     return -1;
  1013.   }
  1014.   // sizes
  1015.   theInlineSize = theColumn->getInlineSize();
  1016.   thePartSize = theColumn->getPartSize();
  1017.   theStripeSize = theColumn->getStripeSize();
  1018.   // sanity check
  1019.   assert((NDB_BLOB_HEAD_SIZE << 2) == sizeof(Head));
  1020.   assert(theColumn->m_attrSize * theColumn->m_arraySize == sizeof(Head) + theInlineSize);
  1021.   if (thePartSize > 0) {
  1022.     const NdbDictionary::Table* bt = NULL;
  1023.     const NdbDictionary::Column* bc = NULL;
  1024.     if (theStripeSize == 0 ||
  1025.         (bt = theColumn->getBlobTable()) == NULL ||
  1026.         (bc = bt->getColumn("DATA")) == NULL ||
  1027.         bc->getType() != partType ||
  1028.         bc->getLength() != (int)thePartSize) {
  1029.       setErrorCode(NdbBlobImpl::ErrTable);
  1030.       return -1;
  1031.     }
  1032.     theBlobTable = &NdbTableImpl::getImpl(*bt);
  1033.   }
  1034.   // buffers
  1035.   theKeyBuf.alloc(theTable->m_sizeOfKeysInWords << 2);
  1036.   theAccessKeyBuf.alloc(theAccessTable->m_sizeOfKeysInWords << 2);
  1037.   theHeadInlineBuf.alloc(sizeof(Head) + theInlineSize);
  1038.   theHeadInlineCopyBuf.alloc(sizeof(Head) + theInlineSize);
  1039.   thePartBuf.alloc(thePartSize);
  1040.   theHead = (Head*)theHeadInlineBuf.data;
  1041.   theInlineData = theHeadInlineBuf.data + sizeof(Head);
  1042.   // handle different operation types
  1043.   bool supportedOp = false;
  1044.   if (isKeyOp()) {
  1045.     if (isTableOp()) {
  1046.       // get table key
  1047.       Uint32* data = (Uint32*)theKeyBuf.data;
  1048.       unsigned size = theTable->m_sizeOfKeysInWords;
  1049.       if (theNdbOp->getKeyFromTCREQ(data, size) == -1) {
  1050.         setErrorCode(NdbBlobImpl::ErrUsage);
  1051.         return -1;
  1052.       }
  1053.     }
  1054.     if (isIndexOp()) {
  1055.       // get index key
  1056.       Uint32* data = (Uint32*)theAccessKeyBuf.data;
  1057.       unsigned size = theAccessTable->m_sizeOfKeysInWords;
  1058.       if (theNdbOp->getKeyFromTCREQ(data, size) == -1) {
  1059.         setErrorCode(NdbBlobImpl::ErrUsage);
  1060.         return -1;
  1061.       }
  1062.     }
  1063.     if (isReadOp()) {
  1064.       // add read of head+inline in this op
  1065.       if (getHeadInlineValue(theNdbOp) == -1)
  1066.         return -1;
  1067.     }
  1068.     if (isInsertOp()) {
  1069.       // becomes NULL unless set before execute
  1070.       theNullFlag = true;
  1071.       theLength = 0;
  1072.     }
  1073.     if (isWriteOp()) {
  1074.       // becomes NULL unless set before execute
  1075.       theNullFlag = true;
  1076.       theLength = 0;
  1077.       theHeadInlineUpdateFlag = true;
  1078.     }
  1079.     supportedOp = true;
  1080.   }
  1081.   if (isScanOp()) {
  1082.     // add read of head+inline in this op
  1083.     if (getHeadInlineValue(theNdbOp) == -1)
  1084.       return -1;
  1085.     supportedOp = true;
  1086.   }
  1087.   if (! supportedOp) {
  1088.     setErrorCode(NdbBlobImpl::ErrUsage);
  1089.     return -1;
  1090.   }
  1091.   setState(Prepared);
  1092.   DBG("atPrepare [out]");
  1093.   return 0;
  1094. }
  1095. /*
  1096.  * Before execute of prepared operation.  May add new operations before
  1097.  * this one.  May ask that this operation and all before it (a "batch")
  1098.  * is executed immediately in no-commit mode.  In this case remaining
  1099.  * prepared operations are saved in a separate list.  They are added
  1100.  * back after postExecute.
  1101.  */
  1102. int
  1103. NdbBlob::preExecute(ExecType anExecType, bool& batch)
  1104. {
  1105.   DBG("preExecute [in]");
  1106.   if (theState == Invalid)
  1107.     return -1;
  1108.   assert(theState == Prepared);
  1109.   // handle different operation types
  1110.   assert(isKeyOp());
  1111.   if (isReadOp()) {
  1112.     if (theGetFlag && theGetSetBytes > theInlineSize) {
  1113.       // need blob head before proceeding
  1114.       batch = true;
  1115.     }
  1116.   }
  1117.   if (isInsertOp()) {
  1118.     if (theSetFlag && theGetSetBytes > theInlineSize) {
  1119.       // add ops to write rest of a setValue
  1120.       assert(theSetBuf != NULL);
  1121.       const char* buf = theSetBuf + theInlineSize;
  1122.       Uint32 bytes = theGetSetBytes - theInlineSize;
  1123.       assert(thePos == theInlineSize);
  1124.       if (writeDataPrivate(buf, bytes) == -1)
  1125.         return -1;
  1126.       if (theHeadInlineUpdateFlag) {
  1127.           // add an operation to update head+inline
  1128.           NdbOperation* tOp = theNdbCon->getNdbOperation(theTable);
  1129.           if (tOp == NULL ||
  1130.               tOp->updateTuple() == -1 ||
  1131.               setTableKeyValue(tOp) == -1 ||
  1132.               setHeadInlineValue(tOp) == -1) {
  1133.             setErrorCode(NdbBlobImpl::ErrAbort);
  1134.             return -1;
  1135.           }
  1136.           DBG("add op to update head+inline");
  1137.       }
  1138.     }
  1139.   }
  1140.   if (isTableOp()) {
  1141.     if (isUpdateOp() || isWriteOp() || isDeleteOp()) {
  1142.       // add operation before this one to read head+inline
  1143.       NdbOperation* tOp = theNdbCon->getNdbOperation(theTable, theNdbOp);
  1144.       if (tOp == NULL ||
  1145.           tOp->readTuple() == -1 ||
  1146.           setTableKeyValue(tOp) == -1 ||
  1147.           getHeadInlineValue(tOp) == -1) {
  1148.         setErrorCode(tOp);
  1149.         return -1;
  1150.       }
  1151.       if (isWriteOp()) {
  1152.         tOp->m_abortOption = AO_IgnoreError;
  1153.       }
  1154.       theHeadInlineReadOp = tOp;
  1155.       // execute immediately
  1156.       batch = true;
  1157.       DBG("add op before to read head+inline");
  1158.     }
  1159.   }
  1160.   if (isIndexOp()) {
  1161.     // add op before this one to read table key
  1162.     NdbBlob* tFirstBlob = theNdbOp->theBlobList;
  1163.     if (this == tFirstBlob) {
  1164.       // first blob does it for all
  1165.       if (g_ndb_blob_ok_to_read_index_table) {
  1166.         Uint32 pkAttrId = theAccessTable->getNoOfColumns() - 1;
  1167.         NdbOperation* tOp = theNdbCon->getNdbOperation(theAccessTable, theNdbOp);
  1168.         if (tOp == NULL ||
  1169.             tOp->readTuple() == -1 ||
  1170.             setAccessKeyValue(tOp) == -1 ||
  1171.             tOp->getValue(pkAttrId, theKeyBuf.data) == NULL) {
  1172.           setErrorCode(tOp);
  1173.           return -1;
  1174.         }
  1175.       } else {
  1176.         NdbIndexOperation* tOp = theNdbCon->getNdbIndexOperation(theAccessTable->m_index, theTable, theNdbOp);
  1177.         if (tOp == NULL ||
  1178.             tOp->readTuple() == -1 ||
  1179.             setAccessKeyValue(tOp) == -1 ||
  1180.             getTableKeyValue(tOp) == -1) {
  1181.           setErrorCode(tOp);
  1182.           return -1;
  1183.         }
  1184.       }
  1185.     }
  1186.     DBG("added op before to read table key");
  1187.     if (isUpdateOp() || isDeleteOp()) {
  1188.       // add op before this one to read head+inline via index
  1189.       NdbIndexOperation* tOp = theNdbCon->getNdbIndexOperation(theAccessTable->m_index, theTable, theNdbOp);
  1190.       if (tOp == NULL ||
  1191.           tOp->readTuple() == -1 ||
  1192.           setAccessKeyValue(tOp) == -1 ||
  1193.           getHeadInlineValue(tOp) == -1) {
  1194.         setErrorCode(tOp);
  1195.         return -1;
  1196.       }
  1197.       if (isWriteOp()) {
  1198.         tOp->m_abortOption = AO_IgnoreError;
  1199.       }
  1200.       theHeadInlineReadOp = tOp;
  1201.       // execute immediately
  1202.       batch = true;
  1203.       DBG("added index op before to read head+inline");
  1204.     }
  1205.     if (isWriteOp()) {
  1206.       // XXX until IgnoreError fixed for index op
  1207.       batch = true;
  1208.     }
  1209.   }
  1210.   if (isWriteOp()) {
  1211.     if (theSetFlag) {
  1212.       // write head+inline now
  1213.       theNullFlag = true;
  1214.       theLength = 0;
  1215.       if (theSetBuf != NULL) {
  1216.         Uint32 n = theGetSetBytes;
  1217.         if (n > theInlineSize)
  1218.           n = theInlineSize;
  1219.         assert(thePos == 0);
  1220.         if (writeDataPrivate(theSetBuf, n) == -1)
  1221.           return -1;
  1222.       }
  1223.       if (setHeadInlineValue(theNdbOp) == -1)
  1224.         return -1;
  1225.       // the read op before us may overwrite
  1226.       theHeadInlineCopyBuf.copyfrom(theHeadInlineBuf);
  1227.     }
  1228.   }
  1229.   if (theActiveHook != NULL) {
  1230.     // need blob head for callback
  1231.     batch = true;
  1232.   }
  1233.   DBG("preExecute [out] batch=" << batch);
  1234.   return 0;
  1235. }
  1236. /*
  1237.  * After execute, for any operation.  If already Active, this routine
  1238.  * has been done previously.  Operations which requested a no-commit
  1239.  * batch can add new operations after this one.  They are added before
  1240.  * any remaining prepared operations.
  1241.  */
  1242. int
  1243. NdbBlob::postExecute(ExecType anExecType)
  1244. {
  1245.   DBG("postExecute [in] type=" << anExecType);
  1246.   if (theState == Invalid)
  1247.     return -1;
  1248.   if (theState == Active) {
  1249.     setState(anExecType == NoCommit ? Active : Closed);
  1250.     DBG("postExecute [skip]");
  1251.     return 0;
  1252.   }
  1253.   assert(theState == Prepared);
  1254.   setState(anExecType == NoCommit ? Active : Closed);
  1255.   assert(isKeyOp());
  1256.   if (isIndexOp()) {
  1257.     NdbBlob* tFirstBlob = theNdbOp->theBlobList;
  1258.     if (this != tFirstBlob) {
  1259.       // copy key from first blob
  1260.       assert(theKeyBuf.size == tFirstBlob->theKeyBuf.size);
  1261.       memcpy(theKeyBuf.data, tFirstBlob->theKeyBuf.data, tFirstBlob->theKeyBuf.size);
  1262.     }
  1263.   }
  1264.   if (isReadOp()) {
  1265.     getHeadFromRecAttr();
  1266.     if (setPos(0) == -1)
  1267.       return -1;
  1268.     if (theGetFlag) {
  1269.       assert(theGetSetBytes == 0 || theGetBuf != 0);
  1270.       assert(theGetSetBytes <= theInlineSize || anExecType == NoCommit);
  1271.       Uint32 bytes = theGetSetBytes;
  1272.       if (readDataPrivate(theGetBuf, bytes) == -1)
  1273.         return -1;
  1274.     }
  1275.   }
  1276.   if (isUpdateOp()) {
  1277.     assert(anExecType == NoCommit);
  1278.     getHeadFromRecAttr();
  1279.     if (theSetFlag) {
  1280.       // setValue overwrites everything
  1281.       if (theSetBuf != NULL) {
  1282.         if (truncate(0) == -1)
  1283.           return -1;
  1284.         assert(thePos == 0);
  1285.         if (writeDataPrivate(theSetBuf, theGetSetBytes) == -1)
  1286.           return -1;
  1287.       } else {
  1288.         if (setNull() == -1)
  1289.           return -1;
  1290.       }
  1291.     }
  1292.   }
  1293.   if (isWriteOp() && isTableOp()) {
  1294.     assert(anExecType == NoCommit);
  1295.     if (theHeadInlineReadOp->theError.code == 0) {
  1296.       int tNullFlag = theNullFlag;
  1297.       Uint64 tLength = theLength;
  1298.       Uint64 tPos = thePos;
  1299.       getHeadFromRecAttr();
  1300.       DBG("tuple found");
  1301.       if (truncate(0) == -1)
  1302.         return -1;
  1303.       // restore previous head+inline
  1304.       theHeadInlineBuf.copyfrom(theHeadInlineCopyBuf);
  1305.       theNullFlag = tNullFlag;
  1306.       theLength = tLength;
  1307.       thePos = tPos;
  1308.     } else {
  1309.       if (theHeadInlineReadOp->theError.code != 626) {
  1310.         setErrorCode(theHeadInlineReadOp);
  1311.         return -1;
  1312.       }
  1313.       DBG("tuple not found");
  1314.       /*
  1315.        * Read found no tuple but it is possible that a tuple was
  1316.        * created after the read by another transaction.  Delete all
  1317.        * blob parts which may exist.
  1318.        */
  1319.       if (deletePartsUnknown(0) == -1)
  1320.         return -1;
  1321.     }
  1322.     if (theSetFlag && theGetSetBytes > theInlineSize) {
  1323.       assert(theSetBuf != NULL);
  1324.       const char* buf = theSetBuf + theInlineSize;
  1325.       Uint32 bytes = theGetSetBytes - theInlineSize;
  1326.       assert(thePos == theInlineSize);
  1327.       if (writeDataPrivate(buf, bytes) == -1)
  1328.           return -1;
  1329.     }
  1330.   }
  1331.   if (isWriteOp() && isIndexOp()) {
  1332.     // XXX until IgnoreError fixed for index op
  1333.     if (deletePartsUnknown(0) == -1)
  1334.       return -1;
  1335.     if (theSetFlag && theGetSetBytes > theInlineSize) {
  1336.       assert(theSetBuf != NULL);
  1337.       const char* buf = theSetBuf + theInlineSize;
  1338.       Uint32 bytes = theGetSetBytes - theInlineSize;
  1339.       assert(thePos == theInlineSize);
  1340.       if (writeDataPrivate(buf, bytes) == -1)
  1341.           return -1;
  1342.     }
  1343.   }
  1344.   if (isDeleteOp()) {
  1345.     assert(anExecType == NoCommit);
  1346.     getHeadFromRecAttr();
  1347.     if (deleteParts(0, getPartCount()) == -1)
  1348.       return -1;
  1349.   }
  1350.   setState(anExecType == NoCommit ? Active : Closed);
  1351.   // activation callback
  1352.   if (theActiveHook != NULL) {
  1353.     if (invokeActiveHook() == -1)
  1354.       return -1;
  1355.   }
  1356.   if (anExecType == NoCommit && theHeadInlineUpdateFlag) {
  1357.     NdbOperation* tOp = theNdbCon->getNdbOperation(theTable);
  1358.     if (tOp == NULL ||
  1359.        tOp->updateTuple() == -1 ||
  1360.        setTableKeyValue(tOp) == -1 ||
  1361.        setHeadInlineValue(tOp) == -1) {
  1362.       setErrorCode(NdbBlobImpl::ErrAbort);
  1363.       return -1;
  1364.     }
  1365.     tOp->m_abortOption = AbortOnError;
  1366.     DBG("added op to update head+inline");
  1367.   }
  1368.   DBG("postExecute [out]");
  1369.   return 0;
  1370. }
  1371. /*
  1372.  * Before commit of completed operation.  For write add operation to
  1373.  * update head+inline.
  1374.  */
  1375. int
  1376. NdbBlob::preCommit()
  1377. {
  1378.   DBG("preCommit [in]");
  1379.   if (theState == Invalid)
  1380.     return -1;
  1381.   assert(theState == Active);
  1382.   assert(isKeyOp());
  1383.   if (isInsertOp() || isUpdateOp() || isWriteOp()) {
  1384.     if (theHeadInlineUpdateFlag) {
  1385.         // add an operation to update head+inline
  1386.         NdbOperation* tOp = theNdbCon->getNdbOperation(theTable);
  1387.         if (tOp == NULL ||
  1388.             tOp->updateTuple() == -1 ||
  1389.             setTableKeyValue(tOp) == -1 ||
  1390.             setHeadInlineValue(tOp) == -1) {
  1391.           setErrorCode(NdbBlobImpl::ErrAbort);
  1392.           return -1;
  1393.         }
  1394.         tOp->m_abortOption = AbortOnError;
  1395.         DBG("added op to update head+inline");
  1396.     }
  1397.   }
  1398.   DBG("preCommit [out]");
  1399.   return 0;
  1400. }
  1401. /*
  1402.  * After next scan result.  Handle like read op above.
  1403.  */
  1404. int
  1405. NdbBlob::atNextResult()
  1406. {
  1407.   DBG("atNextResult [in]");
  1408.   if (theState == Invalid)
  1409.     return -1;
  1410.   assert(isScanOp());
  1411.   // get primary key
  1412.   { Uint32* data = (Uint32*)theKeyBuf.data;
  1413.     unsigned size = theTable->m_sizeOfKeysInWords;
  1414.     if (((NdbScanOperation*)theNdbOp)->getKeyFromKEYINFO20(data, size) == -1) {
  1415.       setErrorCode(NdbBlobImpl::ErrUsage);
  1416.       return -1;
  1417.     }
  1418.   }
  1419.   getHeadFromRecAttr();
  1420.   if (setPos(0) == -1)
  1421.     return -1;
  1422.   if (theGetFlag) {
  1423.     assert(theGetSetBytes == 0 || theGetBuf != 0);
  1424.     Uint32 bytes = theGetSetBytes;
  1425.     if (readDataPrivate(theGetBuf, bytes) == -1)
  1426.       return -1;
  1427.   }
  1428.   setState(Active);
  1429.   // activation callback
  1430.   if (theActiveHook != NULL) {
  1431.     if (invokeActiveHook() == -1)
  1432.       return -1;
  1433.   }
  1434.   DBG("atNextResult [out]");
  1435.   return 0;
  1436. }
  1437. // misc
  1438. const NdbDictionary::Column*
  1439. NdbBlob::getColumn()
  1440. {
  1441.   return theColumn;
  1442. }
  1443. // errors
  1444. void
  1445. NdbBlob::setErrorCode(int anErrorCode, bool invalidFlag)
  1446. {
  1447.   DBG("setErrorCode code=" << anErrorCode);
  1448.   theError.code = anErrorCode;
  1449.   // conditionally copy error to operation level
  1450.   if (theNdbOp != NULL && theNdbOp->theError.code == 0)
  1451.     theNdbOp->setErrorCode(theError.code);
  1452.   if (invalidFlag)
  1453.     setState(Invalid);
  1454. }
  1455. void
  1456. NdbBlob::setErrorCode(NdbOperation* anOp, bool invalidFlag)
  1457. {
  1458.   int code = 0;
  1459.   if (anOp != NULL && (code = anOp->theError.code) != 0)
  1460.     ;
  1461.   else if ((code = theNdbCon->theError.code) != 0)
  1462.     ;
  1463.   else if ((code = theNdb->theError.code) != 0)
  1464.     ;
  1465.   else
  1466.     code = NdbBlobImpl::ErrUnknown;
  1467.   setErrorCode(code, invalidFlag);
  1468. }
  1469. void
  1470. NdbBlob::setErrorCode(NdbConnection* aCon, bool invalidFlag)
  1471. {
  1472.   int code = 0;
  1473.   if (theNdbCon != NULL && (code = theNdbCon->theError.code) != 0)
  1474.     ;
  1475.   else if ((code = theNdb->theError.code) != 0)
  1476.     ;
  1477.   else
  1478.     code = NdbBlobImpl::ErrUnknown;
  1479.   setErrorCode(code, invalidFlag);
  1480. }
  1481. // info about all blobs in this operation
  1482. NdbBlob*
  1483. NdbBlob::blobsFirstBlob()
  1484. {
  1485.   return theNdbOp->theBlobList;
  1486. }
  1487. NdbBlob*
  1488. NdbBlob::blobsNextBlob()
  1489. {
  1490.   return theNext;
  1491. }
  1492. // debug
  1493. #ifdef VM_TRACE
  1494. inline int
  1495. NdbBlob::getOperationType() const
  1496. {
  1497.   return theNdbOp != NULL ? theNdbOp->theOperationType : -1;
  1498. }
  1499. NdbOut&
  1500. operator<<(NdbOut& out, const NdbBlob& blob)
  1501. {
  1502.   ndbout << dec << "o=" << blob.getOperationType();
  1503.   ndbout << dec << " s=" << (Uint32) blob.theState;
  1504.   ndbout << dec << " n=" << blob.theNullFlag;;
  1505.   ndbout << dec << " l=" << blob.theLength;
  1506.   ndbout << dec << " p=" << blob.thePos;
  1507.   ndbout << dec << " u=" << (Uint32)blob.theHeadInlineUpdateFlag;
  1508.   ndbout << dec << " g=" << (Uint32)blob.theGetSetBytes;
  1509.   return out;
  1510. }
  1511. #endif