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

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. #define DBTUP_C
  14. #include "Dbtup.hpp"
  15. #include <RefConvert.hpp>
  16. #include <ndb_limits.h>
  17. #include <pc.hpp>
  18. #include <AttributeDescriptor.hpp>
  19. #include "AttributeOffset.hpp"
  20. #include <AttributeHeader.hpp>
  21. #include <Interpreter.hpp>
  22. #include <signaldata/TupCommit.hpp>
  23. #include <signaldata/TupKey.hpp>
  24. #include <NdbSqlUtil.hpp>
  25. /* ----------------------------------------------------------------- */
  26. /* -----------       INIT_STORED_OPERATIONREC         -------------- */
  27. /* ----------------------------------------------------------------- */
  28. int Dbtup::initStoredOperationrec(Operationrec* const regOperPtr,
  29.                                   Uint32 storedId) 
  30. {
  31.   jam();
  32.   StoredProcPtr storedPtr;
  33.   c_storedProcPool.getPtr(storedPtr, storedId);
  34.   if (storedPtr.i != RNIL) {
  35.     if (storedPtr.p->storedCode == ZSCAN_PROCEDURE) {
  36.       storedPtr.p->storedCounter++;
  37.       regOperPtr->firstAttrinbufrec = storedPtr.p->storedLinkFirst;
  38.       regOperPtr->lastAttrinbufrec = storedPtr.p->storedLinkLast;
  39.       regOperPtr->attrinbufLen = storedPtr.p->storedProcLength;
  40.       regOperPtr->currentAttrinbufLen = storedPtr.p->storedProcLength;
  41.       return ZOK;
  42.     }//if
  43.   }//if
  44.   terrorCode = ZSTORED_PROC_ID_ERROR;
  45.   return terrorCode;
  46. }//Dbtup::initStoredOperationrec()
  47. void Dbtup::copyAttrinfo(Signal* signal,
  48.                          Operationrec * const regOperPtr,
  49.                          Uint32* inBuffer)
  50. {
  51.   AttrbufrecPtr copyAttrBufPtr;
  52.   Uint32 RnoOfAttrBufrec = cnoOfAttrbufrec;
  53.   int RbufLen;
  54.   Uint32 RinBufIndex = 0;
  55.   Uint32 Rnext;
  56.   Uint32 Rfirst;
  57.   Uint32 TstoredProcedure = (regOperPtr->storedProcedureId != ZNIL);
  58.   Uint32 RnoFree = cnoFreeAttrbufrec;
  59. //-------------------------------------------------------------------------
  60. // As a prelude to the execution of the TUPKEYREQ we will copy the program
  61. // into the inBuffer to enable easy execution without any complex jumping
  62. // between the buffers. In particular this will make the interpreter less
  63. // complex. Hopefully it does also improve performance.
  64. //-------------------------------------------------------------------------
  65.   copyAttrBufPtr.i = regOperPtr->firstAttrinbufrec;
  66.   while (copyAttrBufPtr.i != RNIL) {
  67.     jam();
  68.     ndbrequire(copyAttrBufPtr.i < RnoOfAttrBufrec);
  69.     ptrAss(copyAttrBufPtr, attrbufrec);
  70.     RbufLen = copyAttrBufPtr.p->attrbuf[ZBUF_DATA_LEN];
  71.     Rnext = copyAttrBufPtr.p->attrbuf[ZBUF_NEXT];
  72.     Rfirst = cfirstfreeAttrbufrec;
  73.     MEMCOPY_NO_WORDS(&inBuffer[RinBufIndex],
  74.                      &copyAttrBufPtr.p->attrbuf[0],
  75.                      RbufLen);
  76.     RinBufIndex += RbufLen;
  77.     if (!TstoredProcedure) {
  78.       copyAttrBufPtr.p->attrbuf[ZBUF_NEXT] = Rfirst;
  79.       cfirstfreeAttrbufrec = copyAttrBufPtr.i;
  80.       RnoFree++;
  81.     }//if
  82.     copyAttrBufPtr.i = Rnext;
  83.   }//while
  84.   cnoFreeAttrbufrec = RnoFree;
  85.   if (TstoredProcedure) {
  86.     jam();
  87.     StoredProcPtr storedPtr;
  88.     c_storedProcPool.getPtr(storedPtr, (Uint32)regOperPtr->storedProcedureId);
  89.     ndbrequire(storedPtr.p->storedCode == ZSCAN_PROCEDURE);
  90.     storedPtr.p->storedCounter--;
  91.     regOperPtr->storedProcedureId = ZNIL;
  92.   }//if
  93.   // Release the ATTRINFO buffers
  94.   regOperPtr->firstAttrinbufrec = RNIL;
  95.   regOperPtr->lastAttrinbufrec = RNIL;
  96. }//Dbtup::copyAttrinfo()
  97. void Dbtup::handleATTRINFOforTUPKEYREQ(Signal* signal,
  98.                                        Uint32 length,
  99.                                        Operationrec * const regOperPtr) 
  100. {
  101.   AttrbufrecPtr TAttrinbufptr;
  102.   TAttrinbufptr.i = cfirstfreeAttrbufrec;
  103.   if ((cfirstfreeAttrbufrec < cnoOfAttrbufrec) &&
  104.       (cnoFreeAttrbufrec > MIN_ATTRBUF)) {
  105.     ptrAss(TAttrinbufptr, attrbufrec);
  106.     MEMCOPY_NO_WORDS(&TAttrinbufptr.p->attrbuf[0],
  107.                      &signal->theData[3],
  108.                      length);
  109.     Uint32 RnoFree = cnoFreeAttrbufrec;
  110.     Uint32 Rnext = TAttrinbufptr.p->attrbuf[ZBUF_NEXT];
  111.     TAttrinbufptr.p->attrbuf[ZBUF_DATA_LEN] = length;
  112.     TAttrinbufptr.p->attrbuf[ZBUF_NEXT] = RNIL;
  113.     AttrbufrecPtr locAttrinbufptr;
  114.     Uint32 RnewLen = regOperPtr->currentAttrinbufLen;
  115.     locAttrinbufptr.i = regOperPtr->lastAttrinbufrec;
  116.     cfirstfreeAttrbufrec = Rnext;
  117.     cnoFreeAttrbufrec = RnoFree - 1;
  118.     RnewLen += length;
  119.     regOperPtr->lastAttrinbufrec = TAttrinbufptr.i;
  120.     regOperPtr->currentAttrinbufLen = RnewLen;
  121.     if (locAttrinbufptr.i == RNIL) {
  122.       regOperPtr->firstAttrinbufrec = TAttrinbufptr.i;
  123.       return;
  124.     } else {
  125.       jam();
  126.       ptrCheckGuard(locAttrinbufptr, cnoOfAttrbufrec, attrbufrec);
  127.       locAttrinbufptr.p->attrbuf[ZBUF_NEXT] = TAttrinbufptr.i;
  128.     }//if
  129.     if (RnewLen < ZATTR_BUFFER_SIZE) {
  130.       return;
  131.     } else {
  132.       jam();
  133.       regOperPtr->transstate = TOO_MUCH_AI;
  134.       return;
  135.     }//if
  136.   } else if (cnoFreeAttrbufrec <= MIN_ATTRBUF) {
  137.     jam();
  138.     regOperPtr->transstate = ERROR_WAIT_TUPKEYREQ;
  139.   } else {
  140.     ndbrequire(false);
  141.   }//if
  142. }//Dbtup::handleATTRINFOforTUPKEYREQ()
  143. void Dbtup::execATTRINFO(Signal* signal) 
  144. {
  145.   OperationrecPtr regOpPtr;
  146.   Uint32 Rsig0 = signal->theData[0];
  147.   Uint32 Rlen = signal->length();
  148.   regOpPtr.i = Rsig0;
  149.   jamEntry();
  150.   ptrCheckGuard(regOpPtr, cnoOfOprec, operationrec);
  151.   if (regOpPtr.p->transstate == IDLE) {
  152.     handleATTRINFOforTUPKEYREQ(signal, Rlen - 3, regOpPtr.p);
  153.     return;
  154.   } else if (regOpPtr.p->transstate == WAIT_STORED_PROCEDURE_ATTR_INFO) {
  155.     storedProcedureAttrInfo(signal, regOpPtr.p, Rlen - 3, 3, false);
  156.     return;
  157.   }//if
  158.   switch (regOpPtr.p->transstate) {
  159.   case ERROR_WAIT_STORED_PROCREQ:
  160.     jam();
  161.   case TOO_MUCH_AI:
  162.     jam();
  163.   case ERROR_WAIT_TUPKEYREQ:
  164.     jam();
  165.     return; /* IGNORE ATTRINFO IN THOSE STATES, WAITING FOR ABORT SIGNAL */
  166.     break;
  167.   case DISCONNECTED:
  168.     jam();
  169.   case STARTED:
  170.     jam();
  171.   default:
  172.     ndbrequire(false);
  173.   }//switch
  174. }//Dbtup::execATTRINFO()
  175. void Dbtup::execTUP_ALLOCREQ(Signal* signal)
  176. {
  177.   OperationrecPtr regOperPtr;
  178.   TablerecPtr regTabPtr;
  179.   FragrecordPtr regFragPtr;
  180.   jamEntry();
  181.   regOperPtr.i = signal->theData[0];
  182.   regFragPtr.i = signal->theData[1];
  183.   regTabPtr.i = signal->theData[2];
  184.   if (!((regOperPtr.i < cnoOfOprec) &&
  185.         (regFragPtr.i < cnoOfFragrec) &&
  186.         (regTabPtr.i < cnoOfTablerec))) {
  187.     ndbrequire(false);
  188.   }//if
  189.   ptrAss(regOperPtr, operationrec);
  190.   ptrAss(regFragPtr, fragrecord);
  191.   ptrAss(regTabPtr, tablerec);
  192. //---------------------------------------------------
  193. /* --- Allocate a tuple as requested by ACC    --- */
  194. //---------------------------------------------------
  195.   PagePtr pagePtr;
  196.   Uint32 pageOffset;
  197.   if (!allocTh(regFragPtr.p,
  198.                regTabPtr.p,
  199.                NORMAL_PAGE,
  200.                signal,
  201.                pageOffset,
  202.                pagePtr)) {
  203.     signal->theData[0] = terrorCode; // Indicate failure
  204.     return;
  205.   }//if
  206.   Uint32 fragPageId = pagePtr.p->pageWord[ZPAGE_FRAG_PAGE_ID_POS];
  207.   Uint32 pageIndex = ((pageOffset - ZPAGE_HEADER_SIZE) /
  208.                        regTabPtr.p->tupheadsize) << 1;
  209.   regOperPtr.p->tableRef = regTabPtr.i;
  210.   regOperPtr.p->fragId = regFragPtr.p->fragmentId;
  211.   regOperPtr.p->realPageId = pagePtr.i;
  212.   regOperPtr.p->fragPageId = fragPageId;
  213.   regOperPtr.p->pageOffset = pageOffset;
  214.   regOperPtr.p->pageIndex  = pageIndex;
  215.   /* -------------------------------------------------------------- */
  216.   /* AN INSERT IS UNDONE BY FREEING THE DATA OCCUPIED BY THE INSERT */
  217.   /* THE ONLY DATA WE HAVE TO LOG EXCEPT THE TYPE, PAGE AND INDEX   */
  218.   /* IS THE AMOUNT OF DATA TO FREE                                  */
  219.   /* -------------------------------------------------------------- */
  220.   if (isUndoLoggingNeeded(regFragPtr.p, fragPageId)) {
  221.     jam();
  222.     cprAddUndoLogRecord(signal,
  223.                         ZLCPR_TYPE_DELETE_TH,
  224.                         fragPageId,
  225.                         pageIndex,
  226.                         regTabPtr.i,
  227.                         regFragPtr.p->fragmentId,
  228.                         regFragPtr.p->checkpointVersion);
  229.   }//if
  230.   //---------------------------------------------------------------
  231.   // Initialise Active operation list by setting the list to empty
  232.   //---------------------------------------------------------------
  233.   ndbrequire(pageOffset < ZWORDS_ON_PAGE);
  234.   pagePtr.p->pageWord[pageOffset] = RNIL;
  235.   signal->theData[0] = 0;
  236.   signal->theData[1] = fragPageId;
  237.   signal->theData[2] = pageIndex;
  238. }//Dbtup::execTUP_ALLOCREQ()
  239. void
  240. Dbtup::setChecksum(Page* const pagePtr, Uint32 tupHeadOffset, Uint32 tupHeadSize)
  241. {
  242.   // 2 == regTabPtr.p->tupChecksumIndex
  243.   pagePtr->pageWord[tupHeadOffset + 2] = 0;
  244.   Uint32 checksum = calculateChecksum(pagePtr, tupHeadOffset, tupHeadSize);
  245.   pagePtr->pageWord[tupHeadOffset + 2] = checksum;
  246. }//Dbtup::setChecksum()
  247. Uint32
  248. Dbtup::calculateChecksum(Page* pagePtr,
  249.                          Uint32 tupHeadOffset,
  250.                          Uint32 tupHeadSize)
  251. {
  252.   Uint32 checksum = 0;
  253.   Uint32 loopStop = tupHeadOffset + tupHeadSize;
  254.   ndbrequire(loopStop <= ZWORDS_ON_PAGE);
  255.   // includes tupVersion
  256.   for (Uint32 i = tupHeadOffset + 1; i < loopStop; i++) {
  257.     checksum ^= pagePtr->pageWord[i];
  258.   }//if
  259.   return checksum;
  260. }//Dbtup::calculateChecksum()
  261. /* ----------------------------------------------------------------- */
  262. /* -----------       INSERT_ACTIVE_OP_LIST            -------------- */
  263. /* ----------------------------------------------------------------- */
  264. void Dbtup::insertActiveOpList(Signal* signal, 
  265.                                OperationrecPtr regOperPtr,
  266.                                Page*  const pagePtr,
  267.                                Uint32 pageOffset) 
  268. {
  269.   OperationrecPtr iaoPrevOpPtr;
  270.   ndbrequire(regOperPtr.p->inActiveOpList == ZFALSE);
  271.   regOperPtr.p->inActiveOpList = ZTRUE;
  272.   ndbrequire(pageOffset < ZWORDS_ON_PAGE);
  273.   iaoPrevOpPtr.i = pagePtr->pageWord[pageOffset];
  274.   pagePtr->pageWord[pageOffset] = regOperPtr.i;
  275.   regOperPtr.p->prevActiveOp = RNIL;
  276.   regOperPtr.p->nextActiveOp = iaoPrevOpPtr.i;
  277.   if (iaoPrevOpPtr.i == RNIL) {
  278.     return;
  279.   } else {
  280.     jam();
  281.     ptrCheckGuard(iaoPrevOpPtr, cnoOfOprec, operationrec);
  282.     iaoPrevOpPtr.p->prevActiveOp = regOperPtr.i;
  283.     if (iaoPrevOpPtr.p->optype == ZDELETE &&
  284.         regOperPtr.p->optype == ZINSERT) {
  285.       jam();
  286.       // mark both
  287.       iaoPrevOpPtr.p->deleteInsertFlag = 1;
  288.       regOperPtr.p->deleteInsertFlag = 1;
  289.     }
  290.     return;
  291.   }//if
  292. }//Dbtup::insertActiveOpList()
  293. void Dbtup::linkOpIntoFragList(OperationrecPtr regOperPtr,
  294.                                Fragrecord* const regFragPtr) 
  295. {
  296.   OperationrecPtr sopTmpOperPtr;
  297.   Uint32 tail = regFragPtr->lastusedOprec;
  298.   ndbrequire(regOperPtr.p->inFragList == ZFALSE);
  299.   regOperPtr.p->inFragList = ZTRUE;
  300.   regOperPtr.p->prevOprecInList = tail;
  301.   regOperPtr.p->nextOprecInList = RNIL;
  302.   sopTmpOperPtr.i = tail;
  303.   if (tail == RNIL) {
  304.     regFragPtr->firstusedOprec = regOperPtr.i;
  305.   } else {
  306.     jam();
  307.     ptrCheckGuard(sopTmpOperPtr, cnoOfOprec, operationrec);
  308.     sopTmpOperPtr.p->nextOprecInList = regOperPtr.i;
  309.   }//if
  310.   regFragPtr->lastusedOprec = regOperPtr.i;
  311. }//Dbtup::linkOpIntoFragList()
  312. /*
  313. This routine is optimised for use from TUPKEYREQ.
  314. This means that a lot of input data is stored in the operation record.
  315. The routine expects the following data in the operation record to be
  316. set-up properly.
  317. Transaction data
  318. 1) transid1
  319. 2) transid2
  320. 3) savePointId
  321. Operation data
  322. 4) optype
  323. 5) dirtyOp
  324. Tuple address
  325. 6) fragPageId
  326. 7) pageIndex
  327. regFragPtr and regTabPtr are references to the table and fragment data and
  328. is read-only.
  329. The routine will set up the following data in the operation record if
  330. returned with success.
  331. Tuple address data
  332. 1) realPageId
  333. 2) fragPageId
  334. 3) pageOffset
  335. 4) pageIndex
  336. Also the pagePtr is an output variable if the routine returns with success.
  337. It's input value can be undefined.
  338. */
  339. bool
  340. Dbtup::getPage(PagePtr& pagePtr,
  341.                Operationrec* const regOperPtr,
  342.                Fragrecord* const regFragPtr,
  343.                Tablerec* const regTabPtr)
  344. {
  345. /* ------------------------------------------------------------------------- */
  346. // GET THE REFERENCE TO THE TUPLE HEADER BY TRANSLATING THE FRAGMENT PAGE ID
  347. // INTO A REAL PAGE ID AND BY USING THE PAGE INDEX TO DERIVE THE PROPER INDEX
  348. // IN THE REAL PAGE.
  349. /* ------------------------------------------------------------------------- */
  350.   pagePtr.i = getRealpid(regFragPtr, regOperPtr->fragPageId);
  351.   regOperPtr->realPageId = pagePtr.i;
  352.   Uint32 RpageIndex = regOperPtr->pageIndex;
  353.   Uint32 Rtupheadsize = regTabPtr->tupheadsize;
  354.   ptrCheckGuard(pagePtr, cnoOfPage, page);
  355.   Uint32 RpageIndexScaled = RpageIndex >> 1;
  356.   ndbrequire((RpageIndex & 1) == 0);
  357.   regOperPtr->pageOffset = ZPAGE_HEADER_SIZE + 
  358.                            (Rtupheadsize * RpageIndexScaled);
  359.   OperationrecPtr leaderOpPtr;
  360.   ndbrequire(regOperPtr->pageOffset < ZWORDS_ON_PAGE);
  361.   leaderOpPtr.i = pagePtr.p->pageWord[regOperPtr->pageOffset];
  362.   if (leaderOpPtr.i == RNIL) {
  363.     return true;
  364.   }//if
  365.   ptrCheckGuard(leaderOpPtr, cnoOfOprec, operationrec);
  366.   bool dirtyRead = ((regOperPtr->optype == ZREAD) &&
  367.                     (regOperPtr->dirtyOp == 1));
  368.   if (dirtyRead) {
  369.     bool sameTrans = ((regOperPtr->transid1 == leaderOpPtr.p->transid1) &&
  370.                       (regOperPtr->transid2 == leaderOpPtr.p->transid2));
  371.     if (!sameTrans) {
  372.       if (!getPageLastCommitted(regOperPtr, leaderOpPtr.p)) {
  373.         return false;
  374.       }//if
  375.       pagePtr.i = regOperPtr->realPageId;
  376.       ptrCheckGuard(pagePtr, cnoOfPage, page);
  377.       return true;
  378.     }//if
  379.   }//if
  380.   if (regOperPtr->optype == ZREAD) {
  381.     /*
  382.     Read uses savepoint id's to find the correct tuple version.
  383.     */
  384.     if (getPageThroughSavePoint(regOperPtr, leaderOpPtr.p)) {
  385.       jam();
  386.       pagePtr.i = regOperPtr->realPageId;
  387.       ptrCheckGuard(pagePtr, cnoOfPage, page);
  388.       return true;
  389.     }
  390.     return false;
  391.   }
  392. //----------------------------------------------------------------------
  393. // Check that no other operation is already active on the tuple. Also
  394. // that abort or commit is not ongoing.
  395. //----------------------------------------------------------------------
  396.   if (leaderOpPtr.p->tupleState == NO_OTHER_OP) {
  397.     jam();
  398.     if ((leaderOpPtr.p->optype == ZDELETE) &&
  399.         (regOperPtr->optype != ZINSERT)) {
  400.       jam();
  401.       terrorCode = ZTUPLE_DELETED_ERROR;
  402.       return false;
  403.     }//if
  404.     return true;
  405.   } else if (leaderOpPtr.p->tupleState == ALREADY_ABORTED) {
  406.     jam();
  407.     terrorCode = ZMUST_BE_ABORTED_ERROR;
  408.     return false;
  409.   } else {
  410.     ndbrequire(false);
  411.   }//if
  412.   return true;
  413. }//Dbtup::getPage()
  414. bool
  415. Dbtup::getPageThroughSavePoint(Operationrec* regOperPtr,
  416.                                Operationrec* leaderOpPtr)
  417. {
  418.   bool found = false;
  419.   OperationrecPtr loopOpPtr;
  420.   loopOpPtr.p = leaderOpPtr;
  421.   while(true) {
  422.     if (regOperPtr->savePointId > loopOpPtr.p->savePointId) {
  423.       jam();
  424.       found = true;
  425.       break;
  426.     }
  427.     if (loopOpPtr.p->nextActiveOp == RNIL) {
  428.       break;
  429.     }
  430.     loopOpPtr.i = loopOpPtr.p->nextActiveOp;
  431.     ptrCheckGuard(loopOpPtr, cnoOfOprec, operationrec);
  432.     jam();
  433.   }
  434.   if (!found) {
  435.     return getPageLastCommitted(regOperPtr, loopOpPtr.p);
  436.   } else {
  437.     if (loopOpPtr.p->optype == ZDELETE) {
  438.       jam();
  439.       terrorCode = ZTUPLE_DELETED_ERROR;
  440.       return false;
  441.     }
  442.     if (loopOpPtr.p->tupleState == ALREADY_ABORTED) {
  443.       /*
  444.       Requested tuple version has already been aborted
  445.       */
  446.       jam();
  447.       terrorCode = ZMUST_BE_ABORTED_ERROR;
  448.       return false;
  449.     }
  450.     bool use_copy;
  451.     if (loopOpPtr.p->prevActiveOp == RNIL) {
  452.       jam();
  453.       /*
  454.       Use original tuple since we are reading from the last written tuple.
  455.       We are the 
  456.       */
  457.       use_copy = false;
  458.     } else {
  459.       /*
  460.       Go forward in time to find a copy of the tuple which this operation
  461.       produced
  462.       */
  463.       loopOpPtr.i = loopOpPtr.p->prevActiveOp;
  464.       ptrCheckGuard(loopOpPtr, cnoOfOprec, operationrec);
  465.       if (loopOpPtr.p->optype == ZDELETE) {
  466.         /*
  467.         This operation was a Delete and thus have no copy tuple attached to
  468.         it. We will move forward to the next that either doesn't exist in
  469.         which case we will return the original tuple of any operation and
  470.         otherwise it must be an insert which contains a copy record.
  471.         */
  472.         if (loopOpPtr.p->prevActiveOp == RNIL) {
  473.           jam();
  474.           use_copy = false;
  475.         } else {
  476.           jam();
  477.           loopOpPtr.i = loopOpPtr.p->prevActiveOp;
  478.           ptrCheckGuard(loopOpPtr, cnoOfOprec, operationrec);
  479.           ndbrequire(loopOpPtr.p->optype == ZINSERT);
  480.           use_copy = true;
  481.         }
  482.       } else if (loopOpPtr.p->optype == ZUPDATE) {
  483.         jam();
  484.         /*
  485.         This operation which was the next in time have a copy which was the
  486.         result of the previous operation which we want to use. Thus use
  487.         the copy tuple of this operation.
  488.         */
  489.         use_copy = true;
  490.       } else {
  491.         /*
  492.         This operation was an insert that happened after an insert or update.
  493.         This is not a possible case.
  494.         */
  495.         ndbrequire(false);
  496.         return false;
  497.       }
  498.     }
  499.     if (use_copy) {
  500.       regOperPtr->realPageId = loopOpPtr.p->realPageIdC;
  501.       regOperPtr->fragPageId = loopOpPtr.p->fragPageIdC;
  502.       regOperPtr->pageIndex = loopOpPtr.p->pageIndexC;
  503.       regOperPtr->pageOffset = loopOpPtr.p->pageOffsetC;
  504.     } else {
  505.       regOperPtr->realPageId = loopOpPtr.p->realPageId;
  506.       regOperPtr->fragPageId = loopOpPtr.p->fragPageId;
  507.       regOperPtr->pageIndex = loopOpPtr.p->pageIndex;
  508.       regOperPtr->pageOffset = loopOpPtr.p->pageOffset;
  509.     }
  510.     return true;
  511.   }
  512. }
  513. bool
  514. Dbtup::getPageLastCommitted(Operationrec* const regOperPtr,
  515.                             Operationrec* const leaderOpPtr)
  516. {
  517. //----------------------------------------------------------------------
  518. // Dirty reads wants to read the latest committed tuple. The latest
  519. // tuple value could be not existing or else we have to find the copy
  520. // tuple. Start by finding the end of the list to find the first operation
  521. // on the record in the ongoing transaction.
  522. //----------------------------------------------------------------------
  523.   jam();
  524.   OperationrecPtr loopOpPtr;
  525.   loopOpPtr.p = leaderOpPtr;
  526.   while (loopOpPtr.p->nextActiveOp != RNIL) {
  527.     jam();
  528.     loopOpPtr.i = loopOpPtr.p->nextActiveOp;
  529.     ptrCheckGuard(loopOpPtr, cnoOfOprec, operationrec);
  530.   }//while
  531.   if (loopOpPtr.p->optype == ZINSERT) {
  532.     jam();
  533. //----------------------------------------------------------------------
  534. // With an insert in the start of the list we know that the tuple did not
  535. // exist before this transaction was started. We don't care if the current
  536. // transaction is in the commit phase since the commit is not really
  537. // completed until the operation is gone from TUP.
  538. //----------------------------------------------------------------------
  539.     terrorCode = ZTUPLE_DELETED_ERROR;
  540.     return false;
  541.   } else {
  542. //----------------------------------------------------------------------
  543. // A successful update and delete as first in the queue means that a tuple
  544. // exist in the committed world. We need to find it.
  545. //----------------------------------------------------------------------
  546.     if (loopOpPtr.p->optype == ZUPDATE) {
  547.       jam();
  548. //----------------------------------------------------------------------
  549. // The first operation was a delete we set our tuple reference to the
  550. // copy tuple of this operation.
  551. //----------------------------------------------------------------------
  552.       regOperPtr->realPageId = loopOpPtr.p->realPageIdC;
  553.       regOperPtr->fragPageId = loopOpPtr.p->fragPageIdC;
  554.       regOperPtr->pageIndex  = loopOpPtr.p->pageIndexC;
  555.       regOperPtr->pageOffset = loopOpPtr.p->pageOffsetC;
  556.     } else if ((loopOpPtr.p->optype == ZDELETE) &&
  557.                (loopOpPtr.p->prevActiveOp == RNIL)) {
  558.       jam();
  559. //----------------------------------------------------------------------
  560. // There was only a delete. The original tuple still is ok.
  561. //----------------------------------------------------------------------
  562.     } else {
  563.       jam();
  564. //----------------------------------------------------------------------
  565. // There was another operation after the delete, this must be an insert
  566. // and we have found our copy tuple there.
  567. //----------------------------------------------------------------------
  568.       loopOpPtr.i = loopOpPtr.p->prevActiveOp;
  569.       ptrCheckGuard(loopOpPtr, cnoOfOprec, operationrec);
  570.       ndbrequire(loopOpPtr.p->optype == ZINSERT);
  571.       regOperPtr->realPageId = loopOpPtr.p->realPageIdC;
  572.       regOperPtr->fragPageId = loopOpPtr.p->fragPageIdC;
  573.       regOperPtr->pageIndex  = loopOpPtr.p->pageIndexC;
  574.       regOperPtr->pageOffset = loopOpPtr.p->pageOffsetC;
  575.     }//if
  576.   }//if
  577.   return true;
  578. }//Dbtup::getPageLastCommitted()
  579. void Dbtup::execTUPKEYREQ(Signal* signal) 
  580. {
  581.   TupKeyReq * const tupKeyReq = (TupKeyReq *)signal->getDataPtr();
  582.   Uint32 RoperPtr = tupKeyReq->connectPtr;
  583.   Uint32 Rtabptr = tupKeyReq->tableRef;
  584.   Uint32 RfragId = tupKeyReq->fragId;
  585.   Uint32 Rstoredid = tupKeyReq->storedProcedure;
  586.   Uint32 Rfragptr = tupKeyReq->fragPtr;
  587.   Uint32 RnoOfOprec = cnoOfOprec;
  588.   Uint32 RnoOfTablerec = cnoOfTablerec;
  589.   Uint32 RnoOfFragrec = cnoOfFragrec;
  590.   operPtr.i = RoperPtr;
  591.   fragptr.i = Rfragptr;
  592.   tabptr.i = Rtabptr;
  593.   jamEntry();
  594.   ndbrequire(((RoperPtr < RnoOfOprec) &&
  595.         (Rtabptr < RnoOfTablerec) &&
  596.         (Rfragptr < RnoOfFragrec)));
  597.   ptrAss(operPtr, operationrec);
  598.   Operationrec * const regOperPtr = operPtr.p;
  599.   ptrAss(fragptr, fragrecord);
  600.   Fragrecord * const regFragPtr = fragptr.p;
  601.   ptrAss(tabptr, tablerec);
  602.   Tablerec* const regTabPtr = tabptr.p;
  603.   Uint32 TrequestInfo = tupKeyReq->request;
  604.   if (regOperPtr->transstate != IDLE) {
  605.     TUPKEY_abort(signal, 39);
  606.     return;
  607.   }//if
  608. /* ----------------------------------------------------------------- */
  609. // Operation is ZREAD when we arrive here so no need to worry about the
  610. // abort process.
  611. /* ----------------------------------------------------------------- */
  612. /* -----------    INITIATE THE OPERATION RECORD       -------------- */
  613. /* ----------------------------------------------------------------- */
  614.   regOperPtr->fragmentPtr = Rfragptr;
  615.   regOperPtr->dirtyOp = TrequestInfo & 1;
  616.   regOperPtr->opSimple = (TrequestInfo >> 1) & 1;
  617.   regOperPtr->interpretedExec = (TrequestInfo >> 10) & 1;
  618.   regOperPtr->optype = (TrequestInfo >> 6) & 0xf;
  619.   // Attributes needed by trigger execution
  620.   regOperPtr->noFiredTriggers = 0;
  621.   regOperPtr->tableRef = Rtabptr;
  622.   regOperPtr->tcOperationPtr = tupKeyReq->opRef;
  623.   regOperPtr->primaryReplica = tupKeyReq->primaryReplica;
  624.   regOperPtr->coordinatorTC = tupKeyReq->coordinatorTC;
  625.   regOperPtr->tcOpIndex = tupKeyReq->tcOpIndex;
  626.   regOperPtr->savePointId = tupKeyReq->savePointId;
  627.   regOperPtr->fragId = RfragId;
  628.   regOperPtr->fragPageId = tupKeyReq->keyRef1;
  629.   regOperPtr->pageIndex = tupKeyReq->keyRef2;
  630.   regOperPtr->attrinbufLen = regOperPtr->logSize = tupKeyReq->attrBufLen;
  631.   regOperPtr->recBlockref = tupKeyReq->applRef;
  632. // Schema Version in tupKeyReq->schemaVersion not used in this version
  633.   regOperPtr->storedProcedureId = Rstoredid;
  634.   regOperPtr->transid1 = tupKeyReq->transId1;
  635.   regOperPtr->transid2 = tupKeyReq->transId2;
  636.   regOperPtr->attroutbufLen = 0;
  637. /* ----------------------------------------------------------------------- */
  638. // INITIALISE TO DEFAULT VALUE
  639. // INIT THE COPY REFERENCE RECORDS TO RNIL TO ENSURE THAT THEIR VALUES
  640. // ARE VALID IF THEY EXISTS
  641. // NO PENDING CHECKPOINT WHEN COPY CREATED (DEFAULT)
  642. // NO TUPLE HAS BEEN ALLOCATED YET
  643. // NO COPY HAS BEEN CREATED YET
  644. /* ----------------------------------------------------------------------- */
  645.   regOperPtr->undoLogged = false;
  646.   regOperPtr->realPageId = RNIL;
  647.   regOperPtr->realPageIdC = RNIL;
  648.   regOperPtr->fragPageIdC = RNIL;
  649.   regOperPtr->pageOffset = ZNIL;
  650.   regOperPtr->pageOffsetC = ZNIL;
  651.   regOperPtr->pageIndexC = ZNIL;
  652.   // version not yet known
  653.   regOperPtr->tupVersion = ZNIL;
  654.   regOperPtr->deleteInsertFlag = 0;
  655.   regOperPtr->tupleState = TUPLE_BLOCKED;
  656.   regOperPtr->changeMask.clear();
  657.   
  658.   if (Rstoredid != ZNIL) {
  659.     ndbrequire(initStoredOperationrec(regOperPtr, Rstoredid) == ZOK);
  660.   }//if
  661.   copyAttrinfo(signal, regOperPtr, &cinBuffer[0]);
  662.   PagePtr pagePtr;
  663.   if (!getPage(pagePtr, regOperPtr, regFragPtr, regTabPtr)) {
  664.     tupkeyErrorLab(signal);
  665.     return;
  666.   }//if
  667.   Uint32 Roptype = regOperPtr->optype;
  668.   if (Roptype == ZREAD) {
  669.     jam();
  670.     if (handleReadReq(signal, regOperPtr, regTabPtr, pagePtr.p) != -1) {
  671.       sendTUPKEYCONF(signal, regOperPtr, 0);
  672. /* ------------------------------------------------------------------------- */
  673. // Read Operations need not to be taken out of any lists. We also do not
  674. // need to wait for commit since there is no changes to commit. Thus we
  675. // prepare the operation record already now for the next operation.
  676. // Write operations have set the state to STARTED above indicating that
  677. // they are waiting for the Commit or Abort decision.
  678. /* ------------------------------------------------------------------------- */
  679.       regOperPtr->transstate = IDLE;
  680.       regOperPtr->currentAttrinbufLen = 0;
  681.     }//if
  682.     return;
  683.   }//if
  684.   linkOpIntoFragList(operPtr, regFragPtr);
  685.   insertActiveOpList(signal,
  686.                      operPtr,
  687.                      pagePtr.p,
  688.                      regOperPtr->pageOffset);
  689.   if (isUndoLoggingBlocked(regFragPtr)) {
  690.     TUPKEY_abort(signal, 38);
  691.     return;
  692.   }//if
  693. /* ---------------------------------------------------------------------- */
  694. // WE SET THE CURRENT ACTIVE OPERATION IN THE TUPLE TO POINT TO OUR
  695. //OPERATION RECORD. IF SEVERAL OPERATIONS WORK ON THIS TUPLE THEY ARE
  696. // LINKED TO OUR OPERATION RECORD. DIRTY READS CAN ACCESS THE COPY
  697. // TUPLE THROUGH OUR OPERATION RECORD.
  698. /* ---------------------------------------------------------------------- */
  699.   if (Roptype == ZINSERT) {
  700.     jam();
  701.     if (handleInsertReq(signal, regOperPtr,
  702.                         regFragPtr, regTabPtr, pagePtr.p) == -1) {
  703.       return;
  704.     }//if
  705.     if (!regTabPtr->tuxCustomTriggers.isEmpty()) {
  706.       jam();
  707.       if (executeTuxInsertTriggers(signal, regOperPtr, regTabPtr) != 0) {
  708.         jam();
  709.         tupkeyErrorLab(signal);
  710.         return;
  711.       }
  712.     }
  713.     checkImmediateTriggersAfterInsert(signal,
  714.                                       regOperPtr,
  715.                                       regTabPtr);
  716.     sendTUPKEYCONF(signal, regOperPtr, regOperPtr->logSize);
  717.     return;
  718.   }//if
  719.   if (regTabPtr->checksumIndicator &&
  720.       (calculateChecksum(pagePtr.p,
  721.                          regOperPtr->pageOffset,
  722.                          regTabPtr->tupheadsize) != 0)) {
  723.     jam();
  724.     terrorCode = ZTUPLE_CORRUPTED_ERROR;
  725.     tupkeyErrorLab(signal);
  726.     return;
  727.   }//if
  728.   if (Roptype == ZUPDATE) {
  729.     jam();
  730.     if (handleUpdateReq(signal, regOperPtr,
  731.                         regFragPtr, regTabPtr, pagePtr.p) == -1) {
  732.       return;
  733.     }//if
  734.     // If update operation is done on primary, 
  735.     // check any after op triggers
  736.     terrorCode = 0;
  737.     if (!regTabPtr->tuxCustomTriggers.isEmpty()) {
  738.       jam();
  739.       if (executeTuxUpdateTriggers(signal, regOperPtr, regTabPtr) != 0) {
  740.         jam();
  741.         tupkeyErrorLab(signal);
  742.         return;
  743.       }
  744.     }
  745.     checkImmediateTriggersAfterUpdate(signal,
  746.                                       regOperPtr,
  747.                                       regTabPtr);
  748.     // XXX use terrorCode for now since all methods are void
  749.     if (terrorCode != 0) {
  750.       tupkeyErrorLab(signal);
  751.       return;
  752.     }
  753.     sendTUPKEYCONF(signal, regOperPtr, regOperPtr->logSize);
  754.     return;
  755.   } else if (Roptype == ZDELETE) {
  756.     jam();
  757.     if (handleDeleteReq(signal, regOperPtr,
  758.                         regFragPtr, regTabPtr, pagePtr.p) == -1) {
  759.       return;
  760.     }//if
  761.     // If delete operation is done on primary, 
  762.     // check any after op triggers
  763.     if (!regTabPtr->tuxCustomTriggers.isEmpty()) {
  764.       jam();
  765.       if (executeTuxDeleteTriggers(signal, regOperPtr, regTabPtr) != 0) {
  766.         jam();
  767.         tupkeyErrorLab(signal);
  768.         return;
  769.       }
  770.     }
  771.     checkImmediateTriggersAfterDelete(signal,
  772.                                       regOperPtr, 
  773.                                       regTabPtr);
  774.     sendTUPKEYCONF(signal, regOperPtr, 0);
  775.     return;
  776.   } else {
  777.     ndbrequire(false);
  778.   }//if
  779. }//Dbtup::execTUPKEYREQ()
  780. /* ---------------------------------------------------------------- */
  781. /* ------------------------ CONFIRM REQUEST ----------------------- */
  782. /* ---------------------------------------------------------------- */
  783. void Dbtup::sendTUPKEYCONF(Signal* signal, 
  784.                            Operationrec * const regOperPtr, 
  785.                            Uint32 TlogSize) 
  786. {
  787.   TupKeyConf * const tupKeyConf = (TupKeyConf *)signal->getDataPtrSend();  
  788.   Uint32 RuserPointer = regOperPtr->userpointer;
  789.   Uint32 RattroutbufLen = regOperPtr->attroutbufLen;
  790.   Uint32 RnoFiredTriggers = regOperPtr->noFiredTriggers;
  791.   BlockReference Ruserblockref = regOperPtr->userblockref;
  792.   Uint32 lastRow = regOperPtr->lastRow;
  793.   regOperPtr->transstate = STARTED;
  794.   regOperPtr->tupleState = NO_OTHER_OP;
  795.   tupKeyConf->userPtr = RuserPointer;
  796.   tupKeyConf->readLength = RattroutbufLen;
  797.   tupKeyConf->writeLength = TlogSize;
  798.   tupKeyConf->noFiredTriggers = RnoFiredTriggers;
  799.   tupKeyConf->lastRow = lastRow;
  800.   EXECUTE_DIRECT(refToBlock(Ruserblockref), GSN_TUPKEYCONF, signal,
  801.  TupKeyConf::SignalLength);
  802.   return;
  803. }//Dbtup::sendTUPKEYCONF()
  804. /* ---------------------------------------------------------------- */
  805. /* ----------------------------- READ  ---------------------------- */
  806. /* ---------------------------------------------------------------- */
  807. int Dbtup::handleReadReq(Signal* signal,
  808.                          Operationrec* const regOperPtr,
  809.                          Tablerec* const regTabPtr,
  810.                          Page* pagePtr)
  811. {
  812.   Uint32 Ttupheadoffset = regOperPtr->pageOffset;
  813.   const BlockReference sendBref = regOperPtr->recBlockref;
  814.   if (regTabPtr->checksumIndicator &&
  815.       (calculateChecksum(pagePtr, Ttupheadoffset,
  816.                          regTabPtr->tupheadsize) != 0)) {
  817.     jam();
  818.     terrorCode = ZTUPLE_CORRUPTED_ERROR;
  819.     tupkeyErrorLab(signal);
  820.     return -1;
  821.   }//if
  822.   Uint32 * dst = &signal->theData[25];
  823.   Uint32 dstLen = (sizeof(signal->theData) / 4) - 25;
  824.   const Uint32 node = refToNode(sendBref);
  825.   if(node != 0 && node != getOwnNodeId()) {
  826.     ;
  827.   } else {
  828.     jam();
  829.     /**
  830.      * execute direct
  831.      */
  832.     dst = &signal->theData[3];
  833.     dstLen = (sizeof(signal->theData) / 4) - 3;
  834.   }
  835.   
  836.   if (regOperPtr->interpretedExec != 1) {
  837.     jam();
  838.     int ret = readAttributes(pagePtr,
  839.      Ttupheadoffset,
  840.      &cinBuffer[0],
  841.      regOperPtr->attrinbufLen,
  842.      dst,
  843.      dstLen,
  844.      false);
  845.     if (ret != -1) {
  846. /* ------------------------------------------------------------------------- */
  847. // We have read all data into coutBuffer. Now send it to the API.
  848. /* ------------------------------------------------------------------------- */
  849.       jam();
  850.       Uint32 TnoOfDataRead= (Uint32) ret;
  851.       regOperPtr->attroutbufLen = TnoOfDataRead;
  852.       sendReadAttrinfo(signal, TnoOfDataRead, regOperPtr);
  853.       return 0;
  854.     }//if
  855.     jam();
  856.     tupkeyErrorLab(signal);
  857.     return -1;
  858.   } else {
  859.     jam();
  860.     regOperPtr->lastRow = 0;
  861.     if (interpreterStartLab(signal, pagePtr, Ttupheadoffset) != -1) {
  862.       return 0;
  863.     }//if
  864.     return -1;
  865.   }//if
  866. }//Dbtup::handleReadReq()
  867. /* ---------------------------------------------------------------- */
  868. /* ---------------------------- UPDATE ---------------------------- */
  869. /* ---------------------------------------------------------------- */
  870. int Dbtup::handleUpdateReq(Signal* signal,
  871.                            Operationrec* const regOperPtr,
  872.                            Fragrecord* const regFragPtr,
  873.                            Tablerec* const regTabPtr,
  874.                            Page* const pagePtr) 
  875. {
  876.   PagePtr copyPagePtr;
  877.   Uint32 tuple_size = regTabPtr->tupheadsize;
  878. //---------------------------------------------------
  879. /* --- MAKE A COPY OF THIS TUPLE ON A COPY PAGE --- */
  880. //---------------------------------------------------
  881.   Uint32 RpageOffsetC;
  882.   if (!allocTh(regFragPtr,
  883.                regTabPtr,
  884.                COPY_PAGE,
  885.                signal,
  886.                RpageOffsetC,
  887.                copyPagePtr)) {
  888.     TUPKEY_abort(signal, 1);
  889.     return -1;
  890.   }//if
  891.   Uint32 RpageIdC = copyPagePtr.i;
  892.   Uint32 RfragPageIdC = copyPagePtr.p->pageWord[ZPAGE_FRAG_PAGE_ID_POS];
  893.   Uint32 indexC = ((RpageOffsetC - ZPAGE_HEADER_SIZE) / tuple_size) << 1;
  894.   regOperPtr->pageIndexC = indexC;
  895.   regOperPtr->fragPageIdC = RfragPageIdC;
  896.   regOperPtr->realPageIdC = RpageIdC;
  897.   regOperPtr->pageOffsetC = RpageOffsetC;
  898.   /* -------------------------------------------------------------- */
  899.   /* IF WE HAVE AN ONGING CHECKPOINT WE HAVE TO LOG THE ALLOCATION  */
  900.   /* OF THE TUPLE HEADER TO BE ABLE TO DELETE IT UPON RESTART       */
  901.   /* THE ONLY DATA EXCEPT THE TYPE, PAGE, INDEX IS THE SIZE TO FREE */
  902.   /* -------------------------------------------------------------- */
  903.   if (isUndoLoggingActive(regFragPtr)) {
  904.     if (isPageUndoLogged(regFragPtr, RfragPageIdC)) {
  905.       jam();
  906.       regOperPtr->undoLogged = true;
  907.       cprAddUndoLogRecord(signal,
  908.                           ZLCPR_TYPE_DELETE_TH,
  909.                           RfragPageIdC,
  910.                           indexC,
  911.                           regOperPtr->tableRef,
  912.                           regOperPtr->fragId,
  913.                           regFragPtr->checkpointVersion);
  914.     }//if
  915.     if (isPageUndoLogged(regFragPtr, regOperPtr->fragPageId)) {
  916.       jam();
  917.       cprAddUndoLogRecord(signal,
  918.                           ZLCPR_TYPE_UPDATE_TH,
  919.                           regOperPtr->fragPageId,
  920.                           regOperPtr->pageIndex,
  921.                           regOperPtr->tableRef,
  922.                           regOperPtr->fragId,
  923.                           regFragPtr->checkpointVersion);
  924.       cprAddData(signal,
  925.                  regFragPtr,
  926.                  regOperPtr->realPageId,
  927.                  tuple_size,
  928.                  regOperPtr->pageOffset);
  929.     }//if
  930.   }//if
  931.   Uint32 RwordCount = tuple_size - 1;
  932.   Uint32 end_dest = RpageOffsetC + tuple_size;
  933.   Uint32 offset = regOperPtr->pageOffset;
  934.   Uint32 end_source = offset + tuple_size;
  935.   ndbrequire(end_dest <= ZWORDS_ON_PAGE && end_source <= ZWORDS_ON_PAGE);
  936.   void* Tdestination = (void*)&copyPagePtr.p->pageWord[RpageOffsetC + 1];
  937.   const void* Tsource = (void*)&pagePtr->pageWord[offset + 1];
  938.   MEMCOPY_NO_WORDS(Tdestination, Tsource, RwordCount);
  939.   Uint32 prev_tup_version;
  940.   // nextActiveOp is before this op in event order
  941.   if (regOperPtr->nextActiveOp == RNIL) {
  942.     jam();
  943.     prev_tup_version = ((const Uint32*)Tsource)[0];
  944.   } else {
  945.     OperationrecPtr prevOperPtr;
  946.     jam();
  947.     prevOperPtr.i = regOperPtr->nextActiveOp;
  948.     ptrCheckGuard(prevOperPtr, cnoOfOprec, operationrec);
  949.     prev_tup_version = prevOperPtr.p->tupVersion;
  950.   }//if
  951.   regOperPtr->tupVersion = (prev_tup_version + 1) &
  952.                            ((1 << ZTUP_VERSION_BITS) - 1);
  953.   // global variable alert
  954.   ndbassert(operationrec + operPtr.i == regOperPtr);
  955.   copyPagePtr.p->pageWord[RpageOffsetC] = operPtr.i;
  956.   return updateStartLab(signal, regOperPtr, regTabPtr, pagePtr);
  957. }//Dbtup::handleUpdateReq()
  958. /* ---------------------------------------------------------------- */
  959. /* ----------------------------- INSERT --------------------------- */
  960. /* ---------------------------------------------------------------- */
  961. int Dbtup::handleInsertReq(Signal* signal,
  962.                            Operationrec* const regOperPtr,
  963.                            Fragrecord* const regFragPtr,
  964.                            Tablerec* const regTabPtr,
  965.                            Page* const pagePtr) 
  966. {
  967.   Uint32 ret_value;
  968.   if (regOperPtr->nextActiveOp != RNIL) {
  969.     jam();
  970.     OperationrecPtr prevExecOpPtr;
  971.     prevExecOpPtr.i = regOperPtr->nextActiveOp;
  972.     ptrCheckGuard(prevExecOpPtr, cnoOfOprec, operationrec);
  973.     if (prevExecOpPtr.p->optype != ZDELETE) {
  974.       terrorCode = ZINSERT_ERROR;
  975.       tupkeyErrorLab(signal);
  976.       return -1;
  977.     }//if
  978.     ret_value = handleUpdateReq(signal, regOperPtr,
  979.                                 regFragPtr, regTabPtr, pagePtr);
  980.   } else {
  981.     jam();
  982.     regOperPtr->tupVersion = 0;
  983.     ret_value = updateStartLab(signal, regOperPtr, regTabPtr, pagePtr);
  984.   }//if
  985.   if (ret_value != (Uint32)-1) {
  986.     if (checkNullAttributes(regOperPtr, regTabPtr)) {
  987.       jam();
  988.       return 0;
  989.     }//if
  990.     TUPKEY_abort(signal, 17);
  991.   }//if
  992.   return -1;
  993. }//Dbtup::handleInsertReq()
  994. /* ---------------------------------------------------------------- */
  995. /* ---------------------------- DELETE ---------------------------- */
  996. /* ---------------------------------------------------------------- */
  997. int Dbtup::handleDeleteReq(Signal* signal,
  998.                            Operationrec* const regOperPtr,
  999.                            Fragrecord* const regFragPtr,
  1000.                            Tablerec* const regTabPtr,
  1001.                            Page* const pagePtr)
  1002. {
  1003.   // delete must set but not increment tupVersion
  1004.   if (regOperPtr->nextActiveOp != RNIL) {
  1005.     OperationrecPtr prevExecOpPtr;
  1006.     prevExecOpPtr.i = regOperPtr->nextActiveOp;
  1007.     ptrCheckGuard(prevExecOpPtr, cnoOfOprec, operationrec);
  1008.     regOperPtr->tupVersion = prevExecOpPtr.p->tupVersion;
  1009.   } else {
  1010.     jam();
  1011.     regOperPtr->tupVersion = pagePtr->pageWord[regOperPtr->pageOffset + 1];
  1012.   }
  1013.   if (isUndoLoggingNeeded(regFragPtr, regOperPtr->fragPageId)) {
  1014.     jam();
  1015.     cprAddUndoLogRecord(signal,
  1016.                         ZINDICATE_NO_OP_ACTIVE,
  1017.                         regOperPtr->fragPageId,
  1018.                         regOperPtr->pageIndex,
  1019.                         regOperPtr->tableRef,
  1020.                         regOperPtr->fragId,
  1021.                         regFragPtr->checkpointVersion);
  1022.   }//if
  1023.   if (regOperPtr->attrinbufLen == 0) {
  1024.     return 0;
  1025.   }//if
  1026. /* ------------------------------------------------------------------------ */
  1027. /* THE APPLICATION WANTS TO READ THE TUPLE BEFORE IT IS DELETED.            */
  1028. /* ------------------------------------------------------------------------ */
  1029.   return handleReadReq(signal, regOperPtr, regTabPtr, pagePtr);
  1030. }//Dbtup::handleDeleteReq()
  1031. int
  1032. Dbtup::updateStartLab(Signal* signal,
  1033.                       Operationrec* const regOperPtr,
  1034.                       Tablerec* const regTabPtr,
  1035.                       Page* const pagePtr)
  1036. {
  1037.   int retValue;
  1038.   if (regOperPtr->optype == ZINSERT) {
  1039.     jam();
  1040.     setNullBits(pagePtr, regTabPtr, regOperPtr->pageOffset);
  1041.   }
  1042.   if (regOperPtr->interpretedExec != 1) {
  1043.     jam();
  1044.     retValue = updateAttributes(pagePtr,
  1045.                                 regOperPtr->pageOffset,
  1046.                                 &cinBuffer[0],
  1047.                                 regOperPtr->attrinbufLen);
  1048.     if (retValue == -1) {
  1049.       tupkeyErrorLab(signal);
  1050.       return -1;
  1051.     }//if
  1052.   } else {
  1053.     jam();
  1054.     retValue = interpreterStartLab(signal, pagePtr, regOperPtr->pageOffset);
  1055.   }//if
  1056.   ndbrequire(regOperPtr->tupVersion != ZNIL);
  1057.   pagePtr->pageWord[regOperPtr->pageOffset + 1] = regOperPtr->tupVersion;
  1058.   if (regTabPtr->checksumIndicator) {
  1059.     jam();
  1060.     setChecksum(pagePtr, regOperPtr->pageOffset, regTabPtr->tupheadsize);
  1061.   }//if
  1062.   return retValue;
  1063. }//Dbtup::updateStartLab()
  1064. void
  1065. Dbtup::setNullBits(Page* const regPage, Tablerec* const regTabPtr, Uint32 pageOffset)
  1066. {
  1067.   Uint32 noOfExtraNullWords = regTabPtr->tupNullWords;
  1068.   Uint32 nullOffsetStart = regTabPtr->tupNullIndex + pageOffset;
  1069.   ndbrequire((noOfExtraNullWords + nullOffsetStart) < ZWORDS_ON_PAGE);
  1070.   for (Uint32 i = 0; i < noOfExtraNullWords; i++) {
  1071.     regPage->pageWord[nullOffsetStart + i] = 0xFFFFFFFF;
  1072.   }//for
  1073. }//Dbtup::setNullBits()
  1074. bool
  1075. Dbtup::checkNullAttributes(Operationrec* const regOperPtr,
  1076.                            Tablerec* const regTabPtr)
  1077. {
  1078. // Implement checking of updating all not null attributes in an insert here.
  1079.   Bitmask<MAXNROFATTRIBUTESINWORDS> attributeMask;  
  1080.   /* 
  1081.    * The idea here is maybe that changeMask is not-null attributes
  1082.    * and must contain notNullAttributeMask.  But:
  1083.    *
  1084.    * 1. changeMask has all bits set on insert
  1085.    * 2. not-null is checked in each UpdateFunction
  1086.    * 3. the code below does not work except trivially due to 1.
  1087.    *
  1088.    * XXX remove or fix
  1089.    */
  1090.   attributeMask.clear();
  1091.   attributeMask.bitOR(regOperPtr->changeMask);
  1092.   attributeMask.bitAND(regTabPtr->notNullAttributeMask);
  1093.   attributeMask.bitXOR(regTabPtr->notNullAttributeMask);
  1094.   if (!attributeMask.isclear()) {
  1095.     return false;
  1096.   }//if
  1097.   return true;
  1098. }//Dbtup::checkNullAttributes()
  1099. /* ---------------------------------------------------------------- */
  1100. /* THIS IS THE START OF THE INTERPRETED EXECUTION OF UPDATES. WE    */
  1101. /* START BY LINKING ALL ATTRINFO'S IN A DOUBLY LINKED LIST (THEY ARE*/
  1102. /* ALREADY IN A LINKED LIST). WE ALLOCATE A REGISTER MEMORY (EQUAL  */
  1103. /* TO AN ATTRINFO RECORD). THE INTERPRETER GOES THROUGH FOUR  PHASES*/
  1104. /* DURING THE FIRST PHASE IT IS ONLY ALLOWED TO READ ATTRIBUTES THAT*/
  1105. /* ARE SENT TO THE CLIENT APPLICATION. DURING THE SECOND PHASE IT IS*/
  1106. /* ALLOWED TO READ FROM ATTRIBUTES INTO REGISTERS, TO UPDATE        */
  1107. /* ATTRIBUTES BASED ON EITHER A CONSTANT VALUE OR A REGISTER VALUE, */
  1108. /* A DIVERSE SET OF OPERATIONS ON REGISTERS ARE AVAILABLE AS WELL.  */
  1109. /* IT IS ALSO POSSIBLE TO PERFORM JUMPS WITHIN THE INSTRUCTIONS THAT*/
  1110. /* BELONGS TO THE SECOND PHASE. ALSO SUBROUTINES CAN BE CALLED IN   */
  1111. /* THIS PHASE. THE THIRD PHASE IS TO AGAIN READ ATTRIBUTES AND      */
  1112. /* FINALLY THE FOURTH PHASE READS SELECTED REGISTERS AND SEND THEM  */
  1113. /* TO THE CLIENT APPLICATION.                                       */
  1114. /* THERE IS A FIFTH REGION WHICH CONTAINS SUBROUTINES CALLABLE FROM */
  1115. /* THE INTERPRETER EXECUTION REGION.                                */
  1116. /* THE FIRST FIVE WORDS WILL GIVE THE LENGTH OF THE FIVEE REGIONS   */
  1117. /*                                                                  */
  1118. /* THIS MEANS THAT FROM THE APPLICATIONS POINT OF VIEW THE DATABASE */
  1119. /* CAN HANDLE SUBROUTINE CALLS WHERE THE CODE IS SENT IN THE REQUEST*/
  1120. /* THE RETURN PARAMETERS ARE FIXED AND CAN EITHER BE GENERATED      */
  1121. /* BEFORE THE EXECUTION OF THE ROUTINE OR AFTER.                    */
  1122. /*                                                                  */
  1123. /* IN LATER VERSIONS WE WILL ADD MORE THINGS LIKE THE POSSIBILITY   */
  1124. /* TO ALLOCATE MEMORY AND USE THIS AS LOCAL STORAGE. IT IS ALSO     */
  1125. /* IMAGINABLE TO HAVE SPECIAL ROUTINES THAT CAN PERFORM CERTAIN     */
  1126. /* OPERATIONS ON BLOB'S DEPENDENT ON WHAT THE BLOB REPRESENTS.      */
  1127. /*                                                                  */
  1128. /*                                                                  */
  1129. /*       -----------------------------------------                  */
  1130. /*       +   INITIAL READ REGION                 +                  */
  1131. /*       -----------------------------------------                  */
  1132. /*       +   INTERPRETED EXECUTE  REGION         +                  */
  1133. /*       -----------------------------------------                  */
  1134. /*       +   FINAL UPDATE REGION                 +                  */
  1135. /*       -----------------------------------------                  */
  1136. /*       +   FINAL READ REGION                   +                  */
  1137. /*       -----------------------------------------                  */
  1138. /*       +   SUBROUTINE REGION                   +                  */
  1139. /*       -----------------------------------------                  */
  1140. /* ---------------------------------------------------------------- */
  1141. /* ---------------------------------------------------------------- */
  1142. /* ----------------- INTERPRETED EXECUTION  ----------------------- */
  1143. /* ---------------------------------------------------------------- */
  1144. int Dbtup::interpreterStartLab(Signal* signal,
  1145.                                Page* const pagePtr,
  1146.                                Uint32 TupHeadOffset) 
  1147. {
  1148.   Operationrec *  const regOperPtr = operPtr.p;
  1149.   Uint32 RtotalLen;
  1150.   int TnoDataRW;
  1151.   Uint32 RinitReadLen = cinBuffer[0];
  1152.   Uint32 RexecRegionLen = cinBuffer[1];
  1153.   Uint32 RfinalUpdateLen = cinBuffer[2];
  1154.   Uint32 RfinalRLen = cinBuffer[3];
  1155.   Uint32 RsubLen = cinBuffer[4];
  1156.   Uint32 RattrinbufLen = regOperPtr->attrinbufLen;
  1157.   const BlockReference sendBref = regOperPtr->recBlockref;
  1158.   Uint32 * dst = &signal->theData[25];
  1159.   Uint32 dstLen = (sizeof(signal->theData) / 4) - 25;
  1160.   const Uint32 node = refToNode(sendBref);
  1161.   if(node != 0 && node != getOwnNodeId()) {
  1162.     ;
  1163.   } else {
  1164.     jam();
  1165.     /**
  1166.      * execute direct
  1167.      */
  1168.     dst = &signal->theData[3];
  1169.     dstLen = (sizeof(signal->theData) / 4) - 3;
  1170.   }
  1171.   
  1172.   RtotalLen = RinitReadLen;
  1173.   RtotalLen += RexecRegionLen;
  1174.   RtotalLen += RfinalUpdateLen;
  1175.   RtotalLen += RfinalRLen;
  1176.   RtotalLen += RsubLen;
  1177.   Uint32 RattroutCounter = 0;
  1178.   Uint32 RinstructionCounter = 5;
  1179.   Uint32 RlogSize = 0;
  1180.   if (((RtotalLen + 5) == RattrinbufLen) &&
  1181.       (RattrinbufLen >= 5) &&
  1182.       (RattrinbufLen < ZATTR_BUFFER_SIZE)) {
  1183.     /* ---------------------------------------------------------------- */
  1184.     // We start by checking consistency. We must have the first five
  1185.     // words of the ATTRINFO to give us the length of the regions. The
  1186.     // size of these regions must be the same as the total ATTRINFO
  1187.     // length and finally the total length must be within the limits.
  1188.     /* ---------------------------------------------------------------- */
  1189.     if (RinitReadLen > 0) {
  1190.       jam();
  1191.       /* ---------------------------------------------------------------- */
  1192.       // The first step that can be taken in the interpreter is to read
  1193.       // data of the tuple before any updates have been applied.
  1194.       /* ---------------------------------------------------------------- */
  1195.       TnoDataRW = readAttributes(pagePtr,
  1196.  TupHeadOffset,
  1197.  &cinBuffer[5],
  1198.  RinitReadLen,
  1199.  &dst[0],
  1200.  dstLen,
  1201.                                  false);
  1202.       if (TnoDataRW != -1) {
  1203. RattroutCounter = TnoDataRW;
  1204. RinstructionCounter += RinitReadLen;
  1205.       } else {
  1206. jam();
  1207. tupkeyErrorLab(signal);
  1208. return -1;
  1209.       }//if
  1210.     }//if
  1211.     if (RexecRegionLen > 0) {
  1212.       jam();
  1213.       /* ---------------------------------------------------------------- */
  1214.       // The next step is the actual interpreted execution. This executes
  1215.       // a register-based virtual machine which can read and write attributes
  1216.       // to and from registers.
  1217.       /* ---------------------------------------------------------------- */
  1218.       Uint32 RsubPC = RinstructionCounter + RfinalUpdateLen + RfinalRLen;     
  1219.       TnoDataRW = interpreterNextLab(signal,
  1220.      pagePtr,
  1221.      TupHeadOffset,
  1222.      &clogMemBuffer[0],
  1223.      &cinBuffer[RinstructionCounter],
  1224.      RexecRegionLen,
  1225.      &cinBuffer[RsubPC],
  1226.      RsubLen,
  1227.      &coutBuffer[0],
  1228.      sizeof(coutBuffer) / 4);
  1229.       if (TnoDataRW != -1) {
  1230. RinstructionCounter += RexecRegionLen;
  1231. RlogSize = TnoDataRW;
  1232.       } else {
  1233. jam();
  1234. return -1;
  1235.       }//if
  1236.     }//if
  1237.     if (RfinalUpdateLen > 0) {
  1238.       jam();
  1239.       /* ---------------------------------------------------------------- */
  1240.       // We can also apply a set of updates without any conditions as part
  1241.       // of the interpreted execution.
  1242.       /* ---------------------------------------------------------------- */
  1243.       if (regOperPtr->optype == ZUPDATE) {
  1244. TnoDataRW = updateAttributes(pagePtr,
  1245.      TupHeadOffset,
  1246.      &cinBuffer[RinstructionCounter],
  1247.      RfinalUpdateLen);
  1248. if (TnoDataRW != -1) {
  1249.   MEMCOPY_NO_WORDS(&clogMemBuffer[RlogSize],
  1250.    &cinBuffer[RinstructionCounter],
  1251.    RfinalUpdateLen);
  1252.   RinstructionCounter += RfinalUpdateLen;
  1253.   RlogSize += RfinalUpdateLen;
  1254. } else {
  1255.   jam();
  1256.   tupkeyErrorLab(signal);
  1257.   return -1;
  1258. }//if
  1259.       } else {
  1260. return TUPKEY_abort(signal, 19);
  1261.       }//if
  1262.     }//if
  1263.     if (RfinalRLen > 0) {
  1264.       jam();
  1265.       /* ---------------------------------------------------------------- */
  1266.       // The final action is that we can also read the tuple after it has
  1267.       // been updated.
  1268.       /* ---------------------------------------------------------------- */
  1269.       TnoDataRW = readAttributes(pagePtr,
  1270.  TupHeadOffset,
  1271.  &cinBuffer[RinstructionCounter],
  1272.  RfinalRLen,
  1273.  &dst[RattroutCounter],
  1274.  (dstLen - RattroutCounter),
  1275.                                  false);
  1276.       if (TnoDataRW != -1) {
  1277. RattroutCounter += TnoDataRW;
  1278.       } else {
  1279. jam();
  1280. tupkeyErrorLab(signal);
  1281. return -1;
  1282.       }//if
  1283.     }//if
  1284.     regOperPtr->logSize = RlogSize;
  1285.     regOperPtr->attroutbufLen = RattroutCounter;
  1286.     sendReadAttrinfo(signal, RattroutCounter, regOperPtr);
  1287.     if (RlogSize > 0) {
  1288.       sendLogAttrinfo(signal, RlogSize, regOperPtr);
  1289.     }//if
  1290.     return 0;
  1291.   } else {
  1292.     return TUPKEY_abort(signal, 22);
  1293.   }//if
  1294. }//Dbtup::interpreterStartLab()
  1295. /* ---------------------------------------------------------------- */
  1296. /*       WHEN EXECUTION IS INTERPRETED WE NEED TO SEND SOME ATTRINFO*/
  1297. /*       BACK TO LQH FOR LOGGING AND SENDING TO BACKUP AND STANDBY  */
  1298. /*       NODES.                                                     */
  1299. /*       INPUT:  LOG_ATTRINFOPTR         WHERE TO FETCH DATA FROM   */
  1300. /*               TLOG_START              FIRST INDEX TO LOG         */
  1301. /*               TLOG_END                LAST INDEX + 1 TO LOG      */
  1302. /* ---------------------------------------------------------------- */
  1303. void Dbtup::sendLogAttrinfo(Signal* signal,
  1304.                             Uint32 TlogSize,
  1305.                             Operationrec *  const regOperPtr)
  1306. {
  1307.   Uint32 TbufferIndex = 0;
  1308.   signal->theData[0] = regOperPtr->userpointer;
  1309.   while (TlogSize > 22) {
  1310.     MEMCOPY_NO_WORDS(&signal->theData[3],
  1311.                      &clogMemBuffer[TbufferIndex],
  1312.                      22);
  1313.     EXECUTE_DIRECT(refToBlock(regOperPtr->userblockref), 
  1314.                    GSN_TUP_ATTRINFO, signal, 25);
  1315.     TbufferIndex += 22;
  1316.     TlogSize -= 22;
  1317.   }//while
  1318.   MEMCOPY_NO_WORDS(&signal->theData[3],
  1319.                    &clogMemBuffer[TbufferIndex],
  1320.                    TlogSize);
  1321.   EXECUTE_DIRECT(refToBlock(regOperPtr->userblockref), 
  1322.                  GSN_TUP_ATTRINFO, signal, 3 + TlogSize);
  1323. }//Dbtup::sendLogAttrinfo()
  1324. inline
  1325. Uint32 
  1326. brancher(Uint32 TheInstruction, Uint32 TprogramCounter)
  1327. {         
  1328.   Uint32 TbranchDirection = TheInstruction >> 31;
  1329.   Uint32 TbranchLength = (TheInstruction >> 16) & 0x7fff;
  1330.   TprogramCounter--;
  1331.   if (TbranchDirection == 1) {
  1332.     jam();
  1333.     /* ---------------------------------------------------------------- */
  1334.     /*       WE JUMP BACKWARDS.                                         */
  1335.     /* ---------------------------------------------------------------- */
  1336.     return (TprogramCounter - TbranchLength);
  1337.   } else {
  1338.     jam();
  1339.     /* ---------------------------------------------------------------- */
  1340.     /*       WE JUMP FORWARD.                                           */
  1341.     /* ---------------------------------------------------------------- */
  1342.     return (TprogramCounter + TbranchLength);
  1343.   }//if
  1344. }//brancher()
  1345. int Dbtup::interpreterNextLab(Signal* signal,
  1346.                               Page* const pagePtr,
  1347.                               Uint32 TupHeadOffset,
  1348.                               Uint32* logMemory,
  1349.                               Uint32* mainProgram,
  1350.                               Uint32 TmainProgLen,
  1351.                               Uint32* subroutineProg,
  1352.                               Uint32 TsubroutineLen,
  1353.       Uint32 * tmpArea,
  1354.       Uint32 tmpAreaSz)
  1355. {
  1356.   register Uint32* TcurrentProgram = mainProgram;
  1357.   register Uint32 TcurrentSize = TmainProgLen;
  1358.   register Uint32 RnoOfInstructions = 0;
  1359.   register Uint32 TprogramCounter = 0;
  1360.   register Uint32 theInstruction;
  1361.   register Uint32 theRegister;
  1362.   Uint32 TdataWritten = 0;
  1363.   Uint32 RstackPtr = 0;
  1364.   union {
  1365.     Uint32 TregMemBuffer[32];
  1366.     Uint64 Tdummy[16];
  1367.   };
  1368.   Uint32 TstackMemBuffer[32];
  1369.   /* ---------------------------------------------------------------- */
  1370.   // Initialise all 8 registers to contain the NULL value.
  1371.   // In this version we can handle 32 and 64 bit unsigned integers.
  1372.   // They are handled as 64 bit values. Thus the 32 most significant
  1373.   // bits are zeroed for 32 bit values.
  1374.   /* ---------------------------------------------------------------- */
  1375.   TregMemBuffer[0] = 0;
  1376.   TregMemBuffer[4] = 0;
  1377.   TregMemBuffer[8] = 0;
  1378.   TregMemBuffer[12] = 0;
  1379.   TregMemBuffer[16] = 0;
  1380.   TregMemBuffer[20] = 0;
  1381.   TregMemBuffer[24] = 0;
  1382.   TregMemBuffer[28] = 0;
  1383.   Uint32 tmpHabitant = ~0;
  1384.   while (RnoOfInstructions < 8000) {
  1385.     /* ---------------------------------------------------------------- */
  1386.     /* EXECUTE THE NEXT INTERPRETER INSTRUCTION.                        */
  1387.     /* ---------------------------------------------------------------- */
  1388.     RnoOfInstructions++;
  1389.     theInstruction = TcurrentProgram[TprogramCounter];
  1390.     theRegister = Interpreter::getReg1(theInstruction) << 2;
  1391.     if (TprogramCounter < TcurrentSize) {
  1392.       TprogramCounter++;
  1393.       switch (Interpreter::getOpCode(theInstruction)) {
  1394.       case Interpreter::READ_ATTR_INTO_REG:
  1395. jam();
  1396. /* ---------------------------------------------------------------- */
  1397. // Read an attribute from the tuple into a register.
  1398. // While reading an attribute we allow the attribute to be an array
  1399. // as long as it fits in the 64 bits of the register.
  1400. /* ---------------------------------------------------------------- */
  1401. {
  1402.   Uint32 theAttrinfo = theInstruction;
  1403.   int TnoDataRW= readAttributes(pagePtr,
  1404. TupHeadOffset,
  1405. &theAttrinfo,
  1406. (Uint32)1,
  1407. &TregMemBuffer[theRegister],
  1408. (Uint32)3,
  1409. false);
  1410.   if (TnoDataRW == 2) {
  1411.     /* ------------------------------------------------------------- */
  1412.     // Two words read means that we get the instruction plus one 32 
  1413.     // word read. Thus we set the register to be a 32 bit register.
  1414.     /* ------------------------------------------------------------- */
  1415.     TregMemBuffer[theRegister] = 0x50;
  1416.             * (Int64*)(TregMemBuffer+theRegister+2) = TregMemBuffer[theRegister+1];
  1417.   } else if (TnoDataRW == 3) {
  1418.     /* ------------------------------------------------------------- */
  1419.     // Three words read means that we get the instruction plus two 
  1420.     // 32 words read. Thus we set the register to be a 64 bit register.
  1421.     /* ------------------------------------------------------------- */
  1422.     TregMemBuffer[theRegister] = 0x60;
  1423.             TregMemBuffer[theRegister+3] = TregMemBuffer[theRegister+2];
  1424.             TregMemBuffer[theRegister+2] = TregMemBuffer[theRegister+1];
  1425.   } else if (TnoDataRW == 1) {
  1426.     /* ------------------------------------------------------------- */
  1427.     // One word read means that we must have read a NULL value. We set
  1428.     // the register to indicate a NULL value.
  1429.     /* ------------------------------------------------------------- */
  1430.     TregMemBuffer[theRegister] = 0;
  1431.     TregMemBuffer[theRegister + 2] = 0;
  1432.     TregMemBuffer[theRegister + 3] = 0;
  1433.   } else if (TnoDataRW == -1) {
  1434.     jam();
  1435.     tupkeyErrorLab(signal);
  1436.     return -1;
  1437.   } else {
  1438.     /* ------------------------------------------------------------- */
  1439.     // Any other return value from the read attribute here is not 
  1440.     // allowed and will lead to a system crash.
  1441.     /* ------------------------------------------------------------- */
  1442.     ndbrequire(false);
  1443.   }//if
  1444.   break;
  1445. }
  1446.       case Interpreter::WRITE_ATTR_FROM_REG:
  1447. jam();
  1448. {
  1449.   Uint32 TattrId = theInstruction >> 16;
  1450.   Uint32 TattrDescrIndex = tabptr.p->tabDescriptor +
  1451.     (TattrId << ZAD_LOG_SIZE);
  1452.   Uint32 TattrDesc1 = tableDescriptor[TattrDescrIndex].tabDescr;
  1453.   Uint32 TregType = TregMemBuffer[theRegister];
  1454.   /* --------------------------------------------------------------- */
  1455.   // Calculate the number of words of this attribute.
  1456.   // We allow writes into arrays as long as they fit into the 64 bit
  1457.   // register size.
  1458.   //TEST_MR See to that TattrNoOfWords can be 
  1459.   // read faster from attribute description.
  1460.   /* --------------------------------------------------------------- */
  1461.   Uint32 TarraySize = (TattrDesc1 >> 16);
  1462.   Uint32 TattrLogLen = (TattrDesc1 >> 4) & 0xf;
  1463.   Uint32 TattrNoOfBits = TarraySize << TattrLogLen;
  1464.   Uint32 TattrNoOfWords = (TattrNoOfBits + 31) >> 5;
  1465.   Uint32 Toptype = operPtr.p->optype;
  1466.   Uint32 TdataForUpdate[3];
  1467.   Uint32 Tlen;
  1468.   AttributeHeader& ah = AttributeHeader::init(&TdataForUpdate[0], 
  1469.       TattrId, TattrNoOfWords);
  1470.   TdataForUpdate[1] = TregMemBuffer[theRegister + 2];
  1471.   TdataForUpdate[2] = TregMemBuffer[theRegister + 3];
  1472.   Tlen = TattrNoOfWords + 1;
  1473.   if (Toptype == ZUPDATE) {
  1474.     if (TattrNoOfWords <= 2) {
  1475.       if (TregType == 0) {
  1476. /* --------------------------------------------------------- */
  1477. // Write a NULL value into the attribute
  1478. /* --------------------------------------------------------- */
  1479. ah.setNULL();
  1480. Tlen = 1;
  1481.       }//if
  1482.       int TnoDataRW= updateAttributes(pagePtr,
  1483.       TupHeadOffset,
  1484.       &TdataForUpdate[0],
  1485.       Tlen);
  1486.       if (TnoDataRW != -1) {
  1487. /* --------------------------------------------------------- */
  1488. // Write the written data also into the log buffer so that it 
  1489. // will be logged.
  1490. /* --------------------------------------------------------- */
  1491. logMemory[TdataWritten + 0] = TdataForUpdate[0];
  1492. logMemory[TdataWritten + 1] = TdataForUpdate[1];
  1493. logMemory[TdataWritten + 2] = TdataForUpdate[2];
  1494. TdataWritten += Tlen;
  1495.       } else {
  1496. tupkeyErrorLab(signal);
  1497. return -1;
  1498.       }//if
  1499.     } else {
  1500.       return TUPKEY_abort(signal, 15);
  1501.     }//if
  1502.   } else {
  1503.     return TUPKEY_abort(signal, 16);
  1504.   }//if
  1505.   break;
  1506. }
  1507.       case Interpreter::LOAD_CONST_NULL:
  1508. jam();
  1509. TregMemBuffer[theRegister] = 0; /* NULL INDICATOR */
  1510. break;
  1511.       case Interpreter::LOAD_CONST16:
  1512. jam();
  1513. TregMemBuffer[theRegister] = 0x50; /* 32 BIT UNSIGNED CONSTANT */
  1514. * (Int64*)(TregMemBuffer+theRegister+2) = theInstruction >> 16;
  1515. break;
  1516.       case Interpreter::LOAD_CONST32:
  1517. jam();
  1518. TregMemBuffer[theRegister] = 0x50; /* 32 BIT UNSIGNED CONSTANT */
  1519. * (Int64*)(TregMemBuffer+theRegister+2) = * 
  1520.   (TcurrentProgram+TprogramCounter);
  1521. TprogramCounter++;
  1522. break;
  1523.       case Interpreter::LOAD_CONST64:
  1524. jam();
  1525. TregMemBuffer[theRegister] = 0x60; /* 64 BIT UNSIGNED CONSTANT */
  1526.         TregMemBuffer[theRegister + 2 ] = * (TcurrentProgram + TprogramCounter++);
  1527.         TregMemBuffer[theRegister + 3 ] = * (TcurrentProgram + TprogramCounter++);
  1528. break;
  1529.       case Interpreter::ADD_REG_REG:
  1530. jam();
  1531. {
  1532.   Uint32 TrightRegister = Interpreter::getReg2(theInstruction) << 2;
  1533.   Uint32 TdestRegister = Interpreter::getReg3(theInstruction) << 2;
  1534.   Uint32 TrightType = TregMemBuffer[TrightRegister];
  1535.   Int64 Tright0 = * (Int64*)(TregMemBuffer + TrightRegister + 2);
  1536.   
  1537.   Uint32 TleftType = TregMemBuffer[theRegister];
  1538.   Int64 Tleft0 = * (Int64*)(TregMemBuffer + theRegister + 2);
  1539.          
  1540.   if ((TleftType | TrightType) != 0) {
  1541.     Uint64 Tdest0 = Tleft0 + Tright0;
  1542.     * (Int64*)(TregMemBuffer+TdestRegister+2) = Tdest0;
  1543.     TregMemBuffer[TdestRegister] = 0x60;
  1544.   } else {
  1545.     return TUPKEY_abort(signal, 20);
  1546.   }
  1547.   break;
  1548. }
  1549.       case Interpreter::SUB_REG_REG:
  1550. jam();
  1551. {
  1552.   Uint32 TrightRegister = Interpreter::getReg2(theInstruction) << 2;
  1553.   Uint32 TdestRegister = Interpreter::getReg3(theInstruction) << 2;
  1554.   Uint32 TrightType = TregMemBuffer[TrightRegister];
  1555.   Int64 Tright0 = * (Int64*)(TregMemBuffer + TrightRegister + 2);
  1556.   
  1557.   Uint32 TleftType = TregMemBuffer[theRegister];
  1558.   Int64 Tleft0 = * (Int64*)(TregMemBuffer + theRegister + 2);
  1559.          
  1560.   if ((TleftType | TrightType) != 0) {
  1561.     Int64 Tdest0 = Tleft0 - Tright0;
  1562.     * (Int64*)(TregMemBuffer+TdestRegister+2) = Tdest0;
  1563.     TregMemBuffer[TdestRegister] = 0x60;
  1564.   } else {
  1565.     return TUPKEY_abort(signal, 20);
  1566.   }
  1567.   break;
  1568. }
  1569.       case Interpreter::BRANCH:
  1570. TprogramCounter = brancher(theInstruction, TprogramCounter);
  1571. break;
  1572.       case Interpreter::BRANCH_REG_EQ_NULL:
  1573. if (TregMemBuffer[theRegister] != 0) {
  1574.   jam();
  1575.   continue;
  1576. } else {
  1577.   jam();
  1578.   TprogramCounter = brancher(theInstruction, TprogramCounter);
  1579. }//if
  1580. break;
  1581.       case Interpreter::BRANCH_REG_NE_NULL:
  1582. if (TregMemBuffer[theRegister] == 0) {
  1583.   jam();
  1584.   continue;
  1585. } else {
  1586.   jam();
  1587.   TprogramCounter = brancher(theInstruction, TprogramCounter);
  1588. }//if
  1589. break;
  1590.       case Interpreter::BRANCH_EQ_REG_REG:
  1591. {
  1592.   Uint32 TrightRegister = Interpreter::getReg2(theInstruction) << 2;
  1593.   Uint32 TleftType = TregMemBuffer[theRegister];
  1594.   Uint32 Tleft0    = TregMemBuffer[theRegister + 2];
  1595.   Uint32 Tleft1    = TregMemBuffer[theRegister + 3];
  1596.   Uint32 TrightType = TregMemBuffer[TrightRegister];
  1597.   Uint32 Tright0 = TregMemBuffer[TrightRegister + 2];
  1598.   Uint32 Tright1 = TregMemBuffer[TrightRegister + 3];
  1599.   if ((TrightType | TleftType) != 0) {
  1600.     jam();
  1601.     if ((Tleft0 == Tright0) && (Tleft1 == Tright1)) {
  1602.       TprogramCounter = brancher(theInstruction, TprogramCounter);
  1603.     }//if
  1604.   } else {
  1605.     return TUPKEY_abort(signal, 23);
  1606.   }//if
  1607.   break;
  1608. }
  1609.       case Interpreter::BRANCH_NE_REG_REG:
  1610. {
  1611.   Uint32 TrightRegister = Interpreter::getReg2(theInstruction) << 2;
  1612.   Uint32 TleftType = TregMemBuffer[theRegister];
  1613.   Uint32 Tleft0    = TregMemBuffer[theRegister + 2];
  1614.   Uint32 Tleft1    = TregMemBuffer[theRegister + 3];
  1615.   Uint32 TrightType = TregMemBuffer[TrightRegister];
  1616.   Uint32 Tright0 = TregMemBuffer[TrightRegister + 2];
  1617.   Uint32 Tright1 = TregMemBuffer[TrightRegister + 3];
  1618.   if ((TrightType | TleftType) != 0) {
  1619.     jam();
  1620.     if ((Tleft0 != Tright0) || (Tleft1 != Tright1)) {
  1621.       TprogramCounter = brancher(theInstruction, TprogramCounter);
  1622.     }//if
  1623.   } else {
  1624.     return TUPKEY_abort(signal, 24);
  1625.   }//if
  1626.   break;
  1627. }
  1628.       case Interpreter::BRANCH_LT_REG_REG:
  1629. {
  1630.   Uint32 TrightRegister = Interpreter::getReg2(theInstruction) << 2;
  1631.   Uint32 TrightType = TregMemBuffer[TrightRegister];
  1632.   Int64 Tright0 = * (Int64*)(TregMemBuffer + TrightRegister + 2);
  1633.   
  1634.   Uint32 TleftType = TregMemBuffer[theRegister];
  1635.   Int64 Tleft0 = * (Int64*)(TregMemBuffer + theRegister + 2);
  1636.          
  1637.   if ((TrightType | TleftType) != 0) {
  1638.     jam();
  1639.     if (Tleft0 < Tright0) {
  1640.       TprogramCounter = brancher(theInstruction, TprogramCounter);
  1641.     }//if
  1642.   } else {
  1643.     return TUPKEY_abort(signal, 24);
  1644.   }//if
  1645.   break;
  1646. }
  1647.       case Interpreter::BRANCH_LE_REG_REG:
  1648. {
  1649.   Uint32 TrightRegister = Interpreter::getReg2(theInstruction) << 2;
  1650.   Uint32 TrightType = TregMemBuffer[TrightRegister];
  1651.   Int64 Tright0 = * (Int64*)(TregMemBuffer + TrightRegister + 2);
  1652.   
  1653.   Uint32 TleftType = TregMemBuffer[theRegister];
  1654.   Int64 Tleft0 = * (Int64*)(TregMemBuffer + theRegister + 2);
  1655.   
  1656.   if ((TrightType | TleftType) != 0) {
  1657.     jam();
  1658.     if (Tleft0 <= Tright0) {
  1659.       TprogramCounter = brancher(theInstruction, TprogramCounter);
  1660.     }//if
  1661.   } else {
  1662.     return TUPKEY_abort(signal, 26);
  1663.   }//if
  1664.   break;
  1665. }
  1666.       case Interpreter::BRANCH_GT_REG_REG:
  1667. {
  1668.   Uint32 TrightRegister = Interpreter::getReg2(theInstruction) << 2;
  1669.   Uint32 TrightType = TregMemBuffer[TrightRegister];
  1670.   Int64 Tright0 = * (Int64*)(TregMemBuffer + TrightRegister + 2);
  1671.   
  1672.   Uint32 TleftType = TregMemBuffer[theRegister];
  1673.   Int64 Tleft0 = * (Int64*)(TregMemBuffer + theRegister + 2);
  1674.   
  1675.   if ((TrightType | TleftType) != 0) {
  1676.     jam();
  1677.     if (Tleft0 > Tright0){
  1678.       TprogramCounter = brancher(theInstruction, TprogramCounter);
  1679.     }//if
  1680.   } else {
  1681.     return TUPKEY_abort(signal, 27);
  1682.   }//if
  1683.   break;
  1684. }
  1685.       case Interpreter::BRANCH_GE_REG_REG:
  1686. {
  1687.   Uint32 TrightRegister = Interpreter::getReg2(theInstruction) << 2;
  1688.   Uint32 TrightType = TregMemBuffer[TrightRegister];
  1689.   Int64 Tright0 = * (Int64*)(TregMemBuffer + TrightRegister + 2);
  1690.   
  1691.   Uint32 TleftType = TregMemBuffer[theRegister];
  1692.   Int64 Tleft0 = * (Int64*)(TregMemBuffer + theRegister + 2);
  1693.   
  1694.   if ((TrightType | TleftType) != 0) {
  1695.     jam();
  1696.     if (Tleft0 >= Tright0){
  1697.       TprogramCounter = brancher(theInstruction, TprogramCounter);
  1698.     }//if
  1699.   } else {
  1700.     return TUPKEY_abort(signal, 28);
  1701.   }//if
  1702.   break;
  1703. }
  1704.       case Interpreter::BRANCH_ATTR_OP_ARG:{
  1705. jam();
  1706. Uint32 cond = Interpreter::getBinaryCondition(theInstruction);
  1707. Uint32 diff = Interpreter::getArrayLengthDiff(theInstruction);
  1708. Uint32 vchr = Interpreter::isVarchar(theInstruction);
  1709.         Uint32 nopad =Interpreter::isNopad(theInstruction);
  1710. Uint32 ins2 = TcurrentProgram[TprogramCounter];
  1711. Uint32 attrId = Interpreter::getBranchCol_AttrId(ins2) << 16;
  1712. Uint32 argLen = Interpreter::getBranchCol_Len(ins2);
  1713. if(tmpHabitant != attrId){
  1714.   Int32 TnoDataR = readAttributes(pagePtr,
  1715.   TupHeadOffset,
  1716.   &attrId, 1,
  1717.   tmpArea, tmpAreaSz,
  1718.                                           false);
  1719.   
  1720.   if (TnoDataR == -1) {
  1721.     jam();
  1722.     tupkeyErrorLab(signal);
  1723.     return -1;
  1724.   }
  1725.   tmpHabitant = attrId;
  1726. }
  1727. AttributeHeader ah(tmpArea[0]);
  1728.         const char* s1 = (char*)&tmpArea[1];
  1729.         const char* s2 = (char*)&TcurrentProgram[TprogramCounter+1];
  1730. Uint32 attrLen = (4 * ah.getDataSize()) - diff;
  1731.         if (vchr) {
  1732. #if NDB_VERSION_MAJOR >= 3
  1733.           bool vok = false;
  1734.           if (attrLen >= 2) {
  1735.             Uint32 vlen = (s1[0] << 8) | s1[1]; // big-endian
  1736.             s1 += 2;
  1737.             attrLen -= 2;
  1738.             if (attrLen >= vlen) {
  1739.               attrLen = vlen;
  1740.               vok = true;
  1741.             }
  1742.           }
  1743.           if (!vok) {
  1744.             terrorCode = ZREGISTER_INIT_ERROR;
  1745.             tupkeyErrorLab(signal);
  1746.             return -1;
  1747.           }
  1748. #else
  1749.           Uint32 tmp;
  1750.           if (attrLen >= 2) {
  1751.             unsigned char* ss = (unsigned char*)&s1[attrLen - 2];
  1752.             tmp = (ss[0] << 8) | ss[1];
  1753.             if (tmp <= attrLen - 2)
  1754.               attrLen = tmp;
  1755.           }
  1756.           // XXX handle bad data
  1757. #endif
  1758.         }
  1759.         bool res = false;
  1760.         switch ((Interpreter::BinaryCondition)cond) {
  1761.         case Interpreter::EQ:
  1762.           res = NdbSqlUtil::char_compare(s1, attrLen, s2, argLen, !nopad) == 0;
  1763.           break;
  1764.         case Interpreter::NE:
  1765.           res = NdbSqlUtil::char_compare(s1, attrLen, s2, argLen, !nopad) != 0;
  1766.           break;
  1767.         // note the condition is backwards
  1768.         case Interpreter::LT:
  1769.           res = NdbSqlUtil::char_compare(s1, attrLen, s2, argLen, !nopad) > 0;
  1770.           break;
  1771.         case Interpreter::LE:
  1772.           res = NdbSqlUtil::char_compare(s1, attrLen, s2, argLen, !nopad) >= 0;
  1773.           break;
  1774.         case Interpreter::GT:
  1775.           res = NdbSqlUtil::char_compare(s1, attrLen, s2, argLen, !nopad) < 0;
  1776.           break;
  1777.         case Interpreter::GE:
  1778.           res = NdbSqlUtil::char_compare(s1, attrLen, s2, argLen, !nopad) <= 0;
  1779.           break;
  1780.         case Interpreter::LIKE:
  1781.           res = NdbSqlUtil::char_like(s1, attrLen, s2, argLen, !nopad);
  1782.           break;
  1783.         case Interpreter::NOT_LIKE:
  1784.           res = ! NdbSqlUtil::char_like(s1, attrLen, s2, argLen, !nopad);
  1785.           break;
  1786.         // XXX handle invalid value
  1787.         }
  1788. #ifdef TRACE_INTERPRETER
  1789.   ndbout_c("cond=%u diff=%d vc=%d nopad=%d attr(%d) = >%.*s<(%d) str=>%.*s<(%d) -> res = %d",
  1790.    cond, diff, vchr, nopad,
  1791.    attrId >> 16, attrLen, s1, attrLen, argLen, s2, argLen, res);
  1792. #endif
  1793.         if (res)
  1794.           TprogramCounter = brancher(theInstruction, TprogramCounter);
  1795.         else {
  1796.           Uint32 tmp = (Interpreter::mod4(argLen) >> 2) + 1;
  1797.           TprogramCounter += tmp;
  1798.         }
  1799. break;
  1800.       }
  1801.       case Interpreter::BRANCH_ATTR_EQ_NULL:{
  1802. jam();
  1803. Uint32 ins2 = TcurrentProgram[TprogramCounter];
  1804. Uint32 attrId = Interpreter::getBranchCol_AttrId(ins2) << 16;
  1805. if(tmpHabitant != attrId){
  1806.   Int32 TnoDataR = readAttributes(pagePtr,
  1807.   TupHeadOffset,
  1808.   &attrId, 1,
  1809.   tmpArea, tmpAreaSz,
  1810.                                           false);
  1811.   
  1812.   if (TnoDataR == -1) {
  1813.     jam();
  1814.     tupkeyErrorLab(signal);
  1815.     return -1;
  1816.   }
  1817.   tmpHabitant = attrId;
  1818. }
  1819. AttributeHeader ah(tmpArea[0]);
  1820. if(ah.isNULL()){
  1821.   TprogramCounter = brancher(theInstruction, TprogramCounter);
  1822. } else {
  1823.   TprogramCounter ++;
  1824. }
  1825. break;
  1826.       }
  1827.       case Interpreter::BRANCH_ATTR_NE_NULL:{
  1828. jam();
  1829. Uint32 ins2 = TcurrentProgram[TprogramCounter];
  1830. Uint32 attrId = Interpreter::getBranchCol_AttrId(ins2) << 16;
  1831. if(tmpHabitant != attrId){
  1832.   Int32 TnoDataR = readAttributes(pagePtr,
  1833.   TupHeadOffset,
  1834.   &attrId, 1,
  1835.   tmpArea, tmpAreaSz,
  1836.                                           false);
  1837.   
  1838.   if (TnoDataR == -1) {
  1839.     jam();
  1840.     tupkeyErrorLab(signal);
  1841.     return -1;
  1842.   }
  1843.   tmpHabitant = attrId;
  1844. }
  1845. AttributeHeader ah(tmpArea[0]);
  1846. if(ah.isNULL()){
  1847.   TprogramCounter ++;
  1848. } else {
  1849.   TprogramCounter = brancher(theInstruction, TprogramCounter);
  1850. }
  1851. break;
  1852.       }
  1853.       case Interpreter::EXIT_OK:
  1854. jam();
  1855. #ifdef TRACE_INTERPRETER
  1856. ndbout_c(" - exit_ok");
  1857. #endif
  1858. return TdataWritten;
  1859.       case Interpreter::EXIT_OK_LAST:
  1860. jam();
  1861. #ifdef TRACE_INTERPRETER
  1862. ndbout_c(" - exit_ok_last");
  1863. #endif
  1864. operPtr.p->lastRow = 1;
  1865. return TdataWritten;
  1866.       case Interpreter::EXIT_REFUSE:
  1867. jam();
  1868. #ifdef TRACE_INTERPRETER
  1869. ndbout_c(" - exit_nok");
  1870. #endif
  1871. terrorCode = theInstruction >> 16;
  1872. return TUPKEY_abort(signal, 29);
  1873.       case Interpreter::CALL:
  1874. jam();
  1875. RstackPtr++;
  1876. if (RstackPtr < 32) {
  1877.   TstackMemBuffer[RstackPtr] = TprogramCounter + 1;
  1878.   TprogramCounter = theInstruction >> 16;
  1879.   if (TprogramCounter < TsubroutineLen) {
  1880.     TcurrentProgram = subroutineProg;
  1881.     TcurrentSize = TsubroutineLen;
  1882.   } else {
  1883.     return TUPKEY_abort(signal, 30);
  1884.   }//if
  1885. } else {
  1886.   return TUPKEY_abort(signal, 31);
  1887. }//if
  1888. break;
  1889.       case Interpreter::RETURN:
  1890. jam();
  1891. if (RstackPtr > 0) {
  1892.   TprogramCounter = TstackMemBuffer[RstackPtr];
  1893.   RstackPtr--;
  1894.   if (RstackPtr == 0) {
  1895.     jam();
  1896.     /* ------------------------------------------------------------- */
  1897.     // We are back to the main program.
  1898.     /* ------------------------------------------------------------- */
  1899.     TcurrentProgram = mainProgram;
  1900.     TcurrentSize = TmainProgLen;
  1901.   }//if
  1902. } else {
  1903.   return TUPKEY_abort(signal, 32);
  1904. }//if
  1905. break;
  1906.       default:
  1907. return TUPKEY_abort(signal, 33);
  1908.       }//switch
  1909.     } else {
  1910.       return TUPKEY_abort(signal, 34);
  1911.     }//if
  1912.   }//while
  1913.   return TUPKEY_abort(signal, 35);
  1914. }//Dbtup::interpreterNextLab()