summaryrefslogtreecommitdiff
path: root/ndb/src/ndbapi/NdbIndexOperation.cpp
diff options
context:
space:
mode:
authormagnus@neptunus.(none) <>2004-04-14 10:53:21 +0200
committermagnus@neptunus.(none) <>2004-04-14 10:53:21 +0200
commit5b3aec2b904a2eb7478240dac2f56d8928fc2362 (patch)
tree3fbbacf704304b69228474b9f03549ccd585a017 /ndb/src/ndbapi/NdbIndexOperation.cpp
parent7d9a9fd93ac4622d596920169a6d6afbd787c377 (diff)
downloadmariadb-git-5b3aec2b904a2eb7478240dac2f56d8928fc2362.tar.gz
Initial revision of NDB Cluster files
Diffstat (limited to 'ndb/src/ndbapi/NdbIndexOperation.cpp')
-rw-r--r--ndb/src/ndbapi/NdbIndexOperation.cpp719
1 files changed, 719 insertions, 0 deletions
diff --git a/ndb/src/ndbapi/NdbIndexOperation.cpp b/ndb/src/ndbapi/NdbIndexOperation.cpp
new file mode 100644
index 00000000000..ee5491d72a8
--- /dev/null
+++ b/ndb/src/ndbapi/NdbIndexOperation.cpp
@@ -0,0 +1,719 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*****************************************************************************
+ * Name: NdbIndexOperation.cpp
+ * Include:
+ * Link:
+ * Author: UABMASD Martin Sköld INN/V Alzato
+ * Date: 2002-04-01
+ * Version: 0.1
+ * Description: Secondary index support
+ * Documentation:
+ * Adjust: 2002-04-01 UABMASD First version.
+ ****************************************************************************/
+
+#include <NdbIndexOperation.hpp>
+#include <NdbResultSet.hpp>
+#include <Ndb.hpp>
+#include <NdbConnection.hpp>
+#include "NdbApiSignal.hpp"
+#include <AttributeHeader.hpp>
+#include <signaldata/TcIndx.hpp>
+#include <signaldata/TcKeyReq.hpp>
+#include <signaldata/IndxKeyInfo.hpp>
+#include <signaldata/IndxAttrInfo.hpp>
+
+#define CHECK_NULL(v) assert(v == NULL); v = NULL;
+
+NdbIndexOperation::NdbIndexOperation(Ndb* aNdb) :
+ NdbOperation(aNdb),
+ m_theIndex(NULL),
+ m_theIndexLen(0),
+ m_theNoOfIndexDefined(0)
+{
+ m_tcReqGSN = GSN_TCINDXREQ;
+ m_attrInfoGSN = GSN_INDXATTRINFO;
+ m_keyInfoGSN = GSN_INDXKEYINFO;
+
+ /**
+ * Change receiver type
+ */
+ theReceiver.init(NdbReceiver::NDB_INDEX_OPERATION, this);
+}
+
+NdbIndexOperation::~NdbIndexOperation()
+{
+}
+
+/*****************************************************************************
+ * int indxInit();
+ *
+ * Return Value: Return 0 : init was successful.
+ * Return -1: In all other case.
+ * Remark: Initiates operation record after allocation.
+ *****************************************************************************/
+int
+NdbIndexOperation::indxInit(NdbIndexImpl * anIndex,
+ NdbTableImpl * aTable,
+ NdbConnection* myConnection)
+{
+ NdbOperation::init(aTable, myConnection);
+
+ switch (anIndex->m_type) {
+ case(NdbDictionary::Index::UniqueHashIndex):
+ break;
+ case(NdbDictionary::Index::Undefined):
+ case(NdbDictionary::Index::HashIndex):
+ case(NdbDictionary::Index::UniqueOrderedIndex):
+ case(NdbDictionary::Index::OrderedIndex):
+ setErrorCodeAbort(4003);
+ return -1;
+ }
+ m_theIndex = anIndex;
+ m_accessTable = anIndex->m_table;
+ m_theIndexLen = 0;
+ m_theNoOfIndexDefined = 0;
+ for (Uint32 i=0; i<MAXNROFTUPLEKEY; i++)
+ for (int j=0; j<3; j++)
+ m_theIndexDefined[i][j] = false;
+
+ TcIndxReq * const tcIndxReq = CAST_PTR(TcIndxReq, theTCREQ->getDataPtrSend());
+ tcIndxReq->scanInfo = 0;
+ theKEYINFOptr = &tcIndxReq->keyInfo[0];
+ theATTRINFOptr = &tcIndxReq->attrInfo[0];
+ return 0;
+}
+
+int NdbIndexOperation::readTuple()
+{
+ // First check that index is unique
+
+ return NdbOperation::readTuple();
+}
+
+int NdbIndexOperation::readTupleExclusive()
+{
+ // First check that index is unique
+
+ return NdbOperation::readTupleExclusive();
+}
+
+int NdbIndexOperation::simpleRead()
+{
+ // First check that index is unique
+
+ return NdbOperation::simpleRead();
+}
+
+int NdbIndexOperation::dirtyRead()
+{
+ // First check that index is unique
+
+ return NdbOperation::dirtyRead();
+}
+
+int NdbIndexOperation::committedRead()
+{
+ // First check that index is unique
+
+ return NdbOperation::committedRead();
+}
+
+int NdbIndexOperation::updateTuple()
+{
+ // First check that index is unique
+
+ return NdbOperation::updateTuple();
+}
+
+int NdbIndexOperation::deleteTuple()
+{
+ // First check that index is unique
+
+ return NdbOperation::deleteTuple();
+}
+
+int NdbIndexOperation::dirtyUpdate()
+{
+ // First check that index is unique
+
+ return NdbOperation::dirtyUpdate();
+}
+
+int NdbIndexOperation::interpretedUpdateTuple()
+{
+ // First check that index is unique
+
+ return NdbOperation::interpretedUpdateTuple();
+}
+
+int NdbIndexOperation::interpretedDeleteTuple()
+{
+ // First check that index is unique
+
+ return NdbOperation::interpretedDeleteTuple();
+}
+
+int NdbIndexOperation::equal_impl(const NdbColumnImpl* tAttrInfo,
+ const char* aValuePassed,
+ Uint32 aVariableKeyLen)
+{
+ register Uint32 tAttrId;
+
+ Uint32 tData;
+ Uint32 tKeyInfoPosition;
+ const char* aValue = aValuePassed;
+ Uint32 tempData[1024];
+
+ if ((theStatus == OperationDefined) &&
+ (aValue != NULL) &&
+ (tAttrInfo != NULL )) {
+ /************************************************************************
+ * Start by checking that the attribute is an index key.
+ * This value is also the word order in the tuple key of this
+ * tuple key attribute.
+ * Then check that this tuple key has not already been defined.
+ * Finally check if all tuple key attributes have been defined. If
+ * this is true then set Operation state to tuple key defined.
+ ************************************************************************/
+ tAttrId = tAttrInfo->m_attrId;
+ tKeyInfoPosition = tAttrInfo->m_keyInfoPos;
+ Uint32 i = 0;
+
+ // Check that the attribute is part if the index attributes
+ // by checking if it is a primary key attribute of index table
+ if (tAttrInfo->m_pk) {
+ Uint32 tKeyDefined = theTupleKeyDefined[0][2];
+ Uint32 tKeyAttrId = theTupleKeyDefined[0][0];
+ do {
+ if (tKeyDefined == false) {
+ goto keyEntryFound;
+ } else {
+ if (tKeyAttrId != tAttrId) {
+ /******************************************************************
+ * We read the key defined variable in advance.
+ * It could potentially read outside its area when
+ * i = MAXNROFTUPLEKEY - 1,
+ * it is not a problem as long as the variable
+ * theTupleKeyDefined is defined
+ * in the middle of the object.
+ * Reading wrong data and not using it causes no problems.
+ *****************************************************************/
+ i++;
+ tKeyAttrId = theTupleKeyDefined[i][0];
+ tKeyDefined = theTupleKeyDefined[i][2];
+ continue;
+ } else {
+ goto equal_error2;
+ }//if
+ }//if
+ } while (i < MAXNROFTUPLEKEY);
+ goto equal_error2;
+ } else {
+ goto equal_error1;
+ }
+ /**************************************************************************
+ * Now it is time to retrieve the tuple key data from the pointer supplied
+ * by the application.
+ * We have to retrieve the size of the attribute in words and bits.
+ *************************************************************************/
+ keyEntryFound:
+ m_theIndexDefined[i][0] = tAttrId;
+ m_theIndexDefined[i][1] = tKeyInfoPosition;
+ m_theIndexDefined[i][2] = true;
+
+ Uint32 sizeInBytes = tAttrInfo->m_attrSize * tAttrInfo->m_arraySize;
+ Uint32 bitsInLastWord = 8 * (sizeInBytes & 3) ;
+ Uint32 totalSizeInWords = (sizeInBytes + 3)/4;// Inc. bits in last word
+ Uint32 sizeInWords = sizeInBytes / 4; // Exc. bits in last word
+
+ if (true){ //tArraySize != 0) {
+ Uint32 tIndexLen = m_theIndexLen;
+
+ m_theIndexLen = tIndexLen + totalSizeInWords;
+ if ((aVariableKeyLen == sizeInBytes) ||
+ (aVariableKeyLen == 0)) {
+ ;
+ } else {
+ goto equal_error3;
+ }
+ }
+#if 0
+ else {
+ /************************************************************************
+ * The attribute is a variable array. We need to use the length parameter
+ * to know the size of this attribute in the key information and
+ * variable area. A key is however not allowed to be larger than 4
+ * kBytes and this is checked for variable array attributes
+ * used as keys.
+ ***********************************************************************/
+ Uint32 tMaxVariableKeyLenInWord = (MAXTUPLEKEYLENOFATTERIBUTEINWORD -
+ tKeyInfoPosition);
+ tAttrSizeInBits = aVariableKeyLen << 3;
+ tAttrSizeInWords = tAttrSizeInBits >> 5;
+ tAttrBitsInLastWord = tAttrSizeInBits - (tAttrSizeInWords << 5);
+ tAttrLenInWords = ((tAttrSizeInBits + 31) >> 5);
+ if (tAttrLenInWords > tMaxVariableKeyLenInWord) {
+ setErrorCodeAbort(4207);
+ return -1;
+ }//if
+ m_theIndexLen = m_theIndexLen + tAttrLenInWords;
+ }//if
+#endif
+
+ /*************************************************************************
+ * Check if the pointer of the value passed is aligned on a 4 byte
+ * boundary. If so only assign the pointer to the internal variable
+ * aValue. If it is not aligned then we start by copying the value to
+ * tempData and use this as aValue instead.
+ *************************************************************************/
+ const int attributeSize = sizeInBytes;
+ const int slack = sizeInBytes & 3;
+ int tDistrKey = tAttrInfo->m_distributionKey;
+ int tDistrGroup = tAttrInfo->m_distributionGroup;
+ if ((((UintPtr)aValue & 3) != 0) || (slack != 0)){
+ memcpy(&tempData[0], aValue, attributeSize);
+ aValue = (char*)&tempData[0];
+ if(slack != 0) {
+ char * tmp = (char*)&tempData[0];
+ memset(&tmp[attributeSize], 0, (4 - slack));
+ }//if
+ }//if
+ OperationType tOpType = theOperationType;
+ if ((tDistrKey != 1) && (tDistrGroup != 1)) {
+ ;
+ } else if (tDistrKey == 1) {
+ theDistrKeySize += totalSizeInWords;
+ theDistrKeyIndicator = 1;
+ } else {
+ Uint32 TsizeInBytes = sizeInBytes;
+ Uint32 TbyteOrderFix = 0;
+ char* TcharByteOrderFix = (char*)&TbyteOrderFix;
+ if (tAttrInfo->m_distributionGroupBits == 8) {
+ char tFirstChar = aValue[TsizeInBytes - 2];
+ char tSecondChar = aValue[TsizeInBytes - 2];
+ TcharByteOrderFix[0] = tFirstChar;
+ TcharByteOrderFix[1] = tSecondChar;
+ TcharByteOrderFix[2] = 0x30;
+ TcharByteOrderFix[3] = 0x30;
+ theDistrGroupType = 0;
+ } else {
+ TbyteOrderFix = ((aValue[TsizeInBytes - 2] - 0x30) * 10)
+ + (aValue[TsizeInBytes - 1] - 0x30);
+ theDistrGroupType = 1;
+ }//if
+ theDistributionGroup = TbyteOrderFix;
+ theDistrGroupIndicator = 1;
+ }//if
+ /**************************************************************************
+ * If the operation is an insert request and the attribute is stored then
+ * we also set the value in the stored part through putting the
+ * information in the INDXATTRINFO signals.
+ *************************************************************************/
+ if ((tOpType == InsertRequest) ||
+ (tOpType == WriteRequest)) {
+ if (!tAttrInfo->m_indexOnly){
+ Uint32 ahValue;
+ Uint32 sz = totalSizeInWords;
+ AttributeHeader::init(&ahValue, tAttrId, sz);
+ insertATTRINFO( ahValue );
+ insertATTRINFOloop((Uint32*)aValue, sizeInWords);
+ if (bitsInLastWord != 0) {
+ tData = *(Uint32*)(aValue + (sizeInWords << 2));
+ tData = convertEndian(tData);
+ tData = tData & ((1 << bitsInLastWord) - 1);
+ tData = convertEndian(tData);
+ insertATTRINFO( tData );
+ }//if
+ }//if
+ }//if
+
+ /**************************************************************************
+ * Store the Key information in the TCINDXREQ and INDXKEYINFO signals.
+ *************************************************************************/
+ if (insertKEYINFO(aValue, tKeyInfoPosition,
+ totalSizeInWords, bitsInLastWord) != -1) {
+ /************************************************************************
+ * Add one to number of tuple key attributes defined.
+ * If all have been defined then set the operation state to indicate
+ * that tuple key is defined.
+ * Thereby no more search conditions are allowed in this version.
+ ***********************************************************************/
+ Uint32 tNoIndexDef = m_theNoOfIndexDefined;
+ Uint32 tErrorLine = theErrorLine;
+ int tNoIndexAttrs = m_theIndex->m_columns.size();
+ unsigned char tInterpretInd = theInterpretIndicator;
+ tNoIndexDef++;
+ m_theNoOfIndexDefined = tNoIndexDef;
+ tErrorLine++;
+ theErrorLine = tErrorLine;
+ if (int(tNoIndexDef) == tNoIndexAttrs) {
+ if (tOpType == UpdateRequest) {
+ if (tInterpretInd == 1) {
+ theStatus = GetValue;
+ } else {
+ theStatus = SetValue;
+ }//if
+ return 0;
+ } else if ((tOpType == ReadRequest) || (tOpType == DeleteRequest) ||
+ (tOpType == ReadExclusive)) {
+ theStatus = GetValue;
+ return 0;
+ } else if ((tOpType == InsertRequest) || (tOpType == WriteRequest)) {
+ theStatus = SetValue;
+ return 0;
+ } else {
+ setErrorCodeAbort(4005);
+ return -1;
+ }//if
+ }//if
+ return 0;
+ } else {
+
+ return -1;
+ }//if
+ } else {
+ if (theStatus != OperationDefined) {
+ return -1;
+ }//if
+
+ if (aValue == NULL) {
+ setErrorCodeAbort(4505);
+ return -1;
+ }//if
+
+ if ( tAttrInfo == NULL ) {
+ setErrorCodeAbort(4004);
+ return -1;
+ }//if
+ }//if
+ return -1;
+
+ equal_error1:
+ setErrorCodeAbort(4205);
+ return -1;
+
+ equal_error2:
+ setErrorCodeAbort(4206);
+ return -1;
+
+ equal_error3:
+ setErrorCodeAbort(4209);
+
+ return -1;
+}
+
+int NdbIndexOperation::executeCursor(int aProcessorId)
+{
+ printf("NdbIndexOperation::executeCursor NYI\n");
+ // NYI
+ return -1;
+}
+void
+NdbIndexOperation::setLastFlag(NdbApiSignal* signal, Uint32 lastFlag)
+{
+ TcIndxReq * const req = CAST_PTR(TcIndxReq, signal->getDataPtrSend());
+ TcKeyReq::setExecuteFlag(req->requestInfo, lastFlag);
+}
+
+int
+NdbIndexOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64 aTransactionId)
+{
+ Uint32 tTransId1, tTransId2;
+ Uint32 tReqInfo;
+ Uint32 tSignalCount = 0;
+ Uint32 tInterpretInd = theInterpretIndicator;
+
+ theErrorLine = 0;
+
+ if (tInterpretInd != 1) {
+ OperationType tOpType = theOperationType;
+ OperationStatus tStatus = theStatus;
+ if ((tOpType == UpdateRequest) ||
+ (tOpType == InsertRequest) ||
+ (tOpType == WriteRequest)) {
+ if (tStatus != SetValue) {
+ setErrorCodeAbort(4506);
+ return -1;
+ }//if
+ } else if ((tOpType == ReadRequest) || (tOpType == ReadExclusive) ||
+ (tOpType == DeleteRequest)) {
+ if (tStatus != GetValue) {
+ setErrorCodeAbort(4506);
+ return -1;
+ }//if
+ } else {
+ setErrorCodeAbort(4507);
+ return -1;
+ }//if
+ } else {
+ if (prepareSendInterpreted() == -1) {
+ return -1;
+ }//if
+ }//if
+
+//-------------------------------------------------------------
+// We start by filling in the first 8 unconditional words of the
+// TCINDXREQ signal.
+//-------------------------------------------------------------
+ TcIndxReq * const tcIndxReq =
+ CAST_PTR(TcIndxReq, theTCREQ->getDataPtrSend());
+
+ Uint32 tTotalCurrAI_Len = theTotalCurrAI_Len;
+ Uint32 tIndexId = m_theIndex->m_indexId;
+ Uint32 tSchemaVersion = m_theIndex->m_version;
+
+ tcIndxReq->apiConnectPtr = aTC_ConnectPtr;
+ tcIndxReq->senderData = ptr2int();
+ tcIndxReq->attrLen = tTotalCurrAI_Len;
+ tcIndxReq->indexId = tIndexId;
+ tcIndxReq->indexSchemaVersion = tSchemaVersion;
+
+ tTransId1 = (Uint32) aTransactionId;
+ tTransId2 = (Uint32) (aTransactionId >> 32);
+
+//-------------------------------------------------------------
+// Simple is simple if simple or both start and commit is set.
+//-------------------------------------------------------------
+// Temporarily disable simple stuff
+ Uint8 tSimpleIndicator = 0;
+// Uint8 tSimpleIndicator = theSimpleIndicator;
+ Uint8 tCommitIndicator = theCommitIndicator;
+ Uint8 tStartIndicator = theStartIndicator;
+// if ((theNdbCon->theLastOpInList == this) && (theCommitIndicator == 0))
+// abort();
+// Temporarily disable simple stuff
+ Uint8 tSimpleAlt = 0;
+// Uint8 tSimpleAlt = tStartIndicator & tCommitIndicator;
+ tSimpleIndicator = tSimpleIndicator | tSimpleAlt;
+
+//-------------------------------------------------------------
+// Simple state is set if start and commit is set and it is
+// a read request. Otherwise it is set to zero.
+//-------------------------------------------------------------
+ Uint8 tReadInd = (theOperationType == ReadRequest);
+ Uint8 tSimpleState = tReadInd & tSimpleAlt;
+ theNdbCon->theSimpleState = tSimpleState;
+
+ tcIndxReq->transId1 = tTransId1;
+ tcIndxReq->transId2 = tTransId2;
+
+ tReqInfo = 0;
+
+ if (tTotalCurrAI_Len <= TcIndxReq::MaxAttrInfo) {
+ tcIndxReq->setAIInTcIndxReq(tReqInfo, tTotalCurrAI_Len);
+ } else {
+ tcIndxReq->setAIInTcIndxReq(tReqInfo, TcIndxReq::MaxAttrInfo);
+ }//if
+
+ tcIndxReq->setSimpleFlag(tReqInfo, tSimpleIndicator);
+ tcIndxReq->setCommitFlag(tReqInfo, tCommitIndicator);
+ tcIndxReq->setStartFlag(tReqInfo, tStartIndicator);
+ const Uint8 tInterpretIndicator = theInterpretIndicator;
+ tcIndxReq->setInterpretedFlag(tReqInfo, tInterpretIndicator);
+
+ Uint8 tDirtyIndicator = theDirtyIndicator;
+ OperationType tOperationType = theOperationType;
+ Uint32 tIndexLen = m_theIndexLen;
+ Uint8 abortOption = theNdbCon->m_abortOption;
+
+ tcIndxReq->setDirtyFlag(tReqInfo, tDirtyIndicator);
+ tcIndxReq->setOperationType(tReqInfo, tOperationType);
+ tcIndxReq->setIndexLength(tReqInfo, tIndexLen);
+ tcIndxReq->setCommitType(tReqInfo, abortOption);
+
+ Uint8 tDistrKeyIndicator = theDistrKeyIndicator;
+ Uint8 tDistrGroupIndicator = theDistrGroupIndicator;
+ Uint8 tDistrGroupType = theDistrGroupType;
+ Uint8 tScanIndicator = theScanInfo & 1;
+
+ tcIndxReq->setDistributionGroupFlag(tReqInfo, tDistrGroupIndicator);
+ tcIndxReq->setDistributionGroupTypeFlag(tReqInfo, tDistrGroupType);
+ tcIndxReq->setDistributionKeyFlag(tReqInfo, tDistrKeyIndicator);
+ tcIndxReq->setScanIndFlag(tReqInfo, tScanIndicator);
+
+ tcIndxReq->requestInfo = tReqInfo;
+
+//-------------------------------------------------------------
+// The next step is to fill in the upto three conditional words.
+//-------------------------------------------------------------
+ Uint32* tOptionalDataPtr = &tcIndxReq->scanInfo;
+ Uint32 tDistrGHIndex = tScanIndicator;
+ Uint32 tDistrKeyIndex = tDistrGHIndex + tDistrGroupIndicator;
+
+ Uint32 tScanInfo = theScanInfo;
+ Uint32 tDistributionGroup = theDistributionGroup;
+ Uint32 tDistrKeySize = theDistrKeySize;
+
+ tOptionalDataPtr[0] = tScanInfo;
+ tOptionalDataPtr[tDistrGHIndex] = tDistributionGroup;
+ tOptionalDataPtr[tDistrKeyIndex] = tDistrKeySize;
+
+//-------------------------------------------------------------
+// The next is step is to compress the key data part of the
+// TCKEYREQ signal.
+//-------------------------------------------------------------
+ Uint32 tKeyIndex = tDistrKeyIndex + tDistrKeyIndicator;
+ Uint32* tKeyDataPtr = &tOptionalDataPtr[tKeyIndex];
+ Uint32 Tdata1 = tcIndxReq->keyInfo[0];
+ Uint32 Tdata2 = tcIndxReq->keyInfo[1];
+ Uint32 Tdata3 = tcIndxReq->keyInfo[2];
+ Uint32 Tdata4 = tcIndxReq->keyInfo[3];
+ Uint32 Tdata5;
+
+ tKeyDataPtr[0] = Tdata1;
+ tKeyDataPtr[1] = Tdata2;
+ tKeyDataPtr[2] = Tdata3;
+ tKeyDataPtr[3] = Tdata4;
+ if (tIndexLen > 4) {
+ Tdata1 = tcIndxReq->keyInfo[4];
+ Tdata2 = tcIndxReq->keyInfo[5];
+ Tdata3 = tcIndxReq->keyInfo[6];
+ Tdata4 = tcIndxReq->keyInfo[7];
+
+ tKeyDataPtr[4] = Tdata1;
+ tKeyDataPtr[5] = Tdata2;
+ tKeyDataPtr[6] = Tdata3;
+ tKeyDataPtr[7] = Tdata4;
+ }//if
+//-------------------------------------------------------------
+// Finally we also compress the INDXATTRINFO part of the signal.
+// We optimise by using the if-statement for sending INDXKEYINFO
+// signals to calculating the new Attrinfo Index.
+//-------------------------------------------------------------
+ Uint32 tAttrInfoIndex;
+
+ if (tIndexLen > TcIndxReq::MaxKeyInfo) {
+ /**
+ * Set transid and TC connect ptr in the INDXKEYINFO signals
+ */
+ NdbApiSignal* tSignal = theFirstKEYINFO;
+ Uint32 remainingKey = tIndexLen - TcIndxReq::MaxKeyInfo;
+
+ do {
+ Uint32* tSigDataPtr = tSignal->getDataPtrSend();
+ NdbApiSignal* tnextSignal = tSignal->next();
+ tSignalCount++;
+ tSigDataPtr[0] = aTC_ConnectPtr;
+ tSigDataPtr[1] = tTransId1;
+ tSigDataPtr[2] = tTransId2;
+ if (remainingKey > IndxKeyInfo::DataLength) {
+ // The signal is full
+ tSignal->setLength(IndxKeyInfo::MaxSignalLength);
+ remainingKey -= IndxKeyInfo::DataLength;
+ }
+ else {
+ // Last signal
+ tSignal->setLength(IndxKeyInfo::HeaderLength + remainingKey);
+ remainingKey = 0;
+ }
+ tSignal = tnextSignal;
+ } while (tSignal != NULL);
+ tAttrInfoIndex = tKeyIndex + TcIndxReq::MaxKeyInfo;
+ } else {
+ tAttrInfoIndex = tKeyIndex + tIndexLen;
+ }//if
+
+//-------------------------------------------------------------
+// Perform the Attrinfo packing in the TCKEYREQ signal started
+// above.
+//-------------------------------------------------------------
+ Uint32* tAIDataPtr = &tOptionalDataPtr[tAttrInfoIndex];
+ Tdata1 = tcIndxReq->attrInfo[0];
+ Tdata2 = tcIndxReq->attrInfo[1];
+ Tdata3 = tcIndxReq->attrInfo[2];
+ Tdata4 = tcIndxReq->attrInfo[3];
+ Tdata5 = tcIndxReq->attrInfo[4];
+
+ theTCREQ->setLength(tcIndxReq->getAIInTcIndxReq(tReqInfo) +
+ tAttrInfoIndex + TcIndxReq::StaticLength);
+ tAIDataPtr[0] = Tdata1;
+ tAIDataPtr[1] = Tdata2;
+ tAIDataPtr[2] = Tdata3;
+ tAIDataPtr[3] = Tdata4;
+ tAIDataPtr[4] = Tdata5;
+
+/***************************************************
+* Send the INDXATTRINFO signals.
+***************************************************/
+ if (tTotalCurrAI_Len > 5) {
+ // Set the last signal's length.
+ NdbApiSignal* tSignal = theFirstATTRINFO;
+ theCurrentATTRINFO->setLength(theAI_LenInCurrAI);
+ do {
+ Uint32* tSigDataPtr = tSignal->getDataPtrSend();
+ NdbApiSignal* tnextSignal = tSignal->next();
+ tSignalCount++;
+ tSigDataPtr[0] = aTC_ConnectPtr;
+ tSigDataPtr[1] = tTransId1;
+ tSigDataPtr[2] = tTransId2;
+ tSignal = tnextSignal;
+ } while (tSignal != NULL);
+ }//if
+ NdbRecAttr* tRecAttrObject = theFirstRecAttr;
+ theStatus = WaitResponse;
+ theCurrentRecAttr = tRecAttrObject;
+
+ return 0;
+}
+
+void NdbIndexOperation::closeScan()
+{
+ printf("NdbIndexOperation::closeScan NYI\n");
+}
+
+/***************************************************************************
+int receiveTCINDXREF( NdbApiSignal* aSignal)
+
+Return Value: Return 0 : send was succesful.
+ Return -1: In all other case.
+Parameters: aSignal: the signal object that contains the TCINDXREF signal from TC.
+Remark: Handles the reception of the TCKEYREF signal.
+***************************************************************************/
+int
+NdbIndexOperation::receiveTCINDXREF( NdbApiSignal* aSignal)
+{
+ const TcIndxRef * const tcIndxRef = CAST_CONSTPTR(TcIndxRef, aSignal->getDataPtr());
+
+ if (checkState_TransId(aSignal) == -1) {
+ return -1;
+ }//if
+
+ theStatus = Finished;
+
+ theNdbCon->theReturnStatus = ReturnFailure;
+ //--------------------------------------------------------------------------//
+ // If the transaction this operation belongs to consists only of simple reads
+ // we set the error code on the transaction object.
+ // If the transaction consists of other types of operations we set
+ // the error code only on the operation since the simple read is not really
+ // part of this transaction and we can not decide the status of the whole
+ // transaction based on this operation.
+ //--------------------------------------------------------------------------//
+ Uint32 errorCode = tcIndxRef->errorCode;
+ if (theNdbCon->theSimpleState == 0) {
+ theError.code = errorCode;
+ theNdbCon->setOperationErrorCodeAbort(errorCode);
+ return theNdbCon->OpCompleteFailure();
+ } else {
+ theError.code = errorCode;
+ return theNdbCon->OpCompleteSuccess();
+ }
+}//NdbIndexOperation::receiveTCINDXREF()
+
+
+