diff options
Diffstat (limited to 'ndb/src/ndbapi/NdbOperationSearch.cpp')
-rw-r--r-- | ndb/src/ndbapi/NdbOperationSearch.cpp | 500 |
1 files changed, 500 insertions, 0 deletions
diff --git a/ndb/src/ndbapi/NdbOperationSearch.cpp b/ndb/src/ndbapi/NdbOperationSearch.cpp new file mode 100644 index 00000000000..42f2b1d10d8 --- /dev/null +++ b/ndb/src/ndbapi/NdbOperationSearch.cpp @@ -0,0 +1,500 @@ +/* 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: NdbOperationSearch.C +Include: +Link: +Author: UABMNST Mona Natterkvist UAB/B/SD +Date: 970829 +Version: 0.1 +Description: Interface between TIS and NDB +Documentation: +Adjust: 971022 UABMNST First version. + 971206 UABRONM + *****************************************************************************/ +#include "API.hpp" + +#include <NdbOperation.hpp> +#include "NdbApiSignal.hpp" +#include <NdbConnection.hpp> +#include <Ndb.hpp> +#include "NdbImpl.hpp" +#include <NdbOut.hpp> +#include "AttrType.hpp" + +#include <AttributeHeader.hpp> +#include <signaldata/TcKeyReq.hpp> +#include "NdbDictionaryImpl.hpp" + +/****************************************************************************** +CondIdType equal(const char* anAttrName, char* aValue, Uint32 aVarKeylen); + +Return Value Return 0 : Equal was successful. + Return -1: In all other case. +Parameters: anAttrName : Attribute name for search condition.. + aValue : Referense to the search value. + aVariableKeylen : The length of key in bytes +Remark: Defines search condition with equality anAttrName. +******************************************************************************/ +int +NdbOperation::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 a tuple 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; + 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: + theTupleKeyDefined[i][0] = tAttrId; + theTupleKeyDefined[i][1] = tKeyInfoPosition; + theTupleKeyDefined[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 tTupKeyLen = theTupKeyLen; + + theTupKeyLen = tTupKeyLen + 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 + theTupKeyLen = theTupKeyLen + 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 ATTRINFO signals. + *****************************************************************************/ + if ((tOpType == InsertRequest) || + (tOpType == WriteRequest)) { + if (!tAttrInfo->m_indexOnly){ + Uint32 ahValue; + const 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 TCKEYREQ and KEYINFO 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 tNoKeysDef = theNoOfTupKeyDefined; + Uint32 tErrorLine = theErrorLine; + int tNoTableKeys = m_currentTable->m_noOfKeys; + unsigned char tInterpretInd = theInterpretIndicator; + tNoKeysDef++; + theNoOfTupKeyDefined = tNoKeysDef; + tErrorLine++; + theErrorLine = tErrorLine; + if (int(tNoKeysDef) == tNoTableKeys) { + 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 + } + + if (aValue == NULL) { + // NULL value in primary key + setErrorCodeAbort(4505); + return -1; + }//if + + if ( tAttrInfo == NULL ) { + // Attribute name not found in table + setErrorCodeAbort(4004); + return -1; + }//if + + if (theStatus == GetValue || theStatus == SetValue){ + // All pk's defined + setErrorCodeAbort(4225); + return -1; + }//if + + // If we come here, set a general errorcode + // and exit + setErrorCodeAbort(4200); + return -1; + + equal_error1: + setErrorCodeAbort(4205); + return -1; + + equal_error2: + setErrorCodeAbort(4206); + return -1; + + equal_error3: + setErrorCodeAbort(4209); + return -1; +} + +/****************************************************************************** + * Uint64 setTupleId( void ) + * + * Return Value: Return > 0: OK + * Return 0 : setTupleId failed + * Parameters: + * Remark: + *****************************************************************************/ +Uint64 +NdbOperation::setTupleId() +{ + if (theStatus != OperationDefined) + { + return 0; + } + Uint64 tTupleId = theNdb->getTupleIdFromNdb(m_currentTable->m_tableId); + if (tTupleId == ~0){ + setErrorCodeAbort(theNdb->theError.code); + return 0; + } + if (equal((Uint32)0, tTupleId) == -1) + return 0; + + return tTupleId; +} + +/****************************************************************************** + * int insertKEYINFO(const char* aValue, aStartPosition, + * anAttrSizeInWords, Uint32 anAttrBitsInLastWord); + * + * Return Value: Return 0 : insertKEYINFO was succesful. + * Return -1: In all other case. + * Parameters: aValue: the data to insert into KEYINFO. + * aStartPosition : Start position for Tuplekey in + * KEYINFO (TCKEYREQ). + * aKeyLenInByte : Length of tuplekey or part of tuplekey + * anAttrBitsInLastWord : Nr of bits in last word. + * Remark: Puts the the data into either TCKEYREQ signal + * or KEYINFO signal. + *****************************************************************************/ +int +NdbOperation::insertKEYINFO(const char* aValue, + register Uint32 aStartPosition, + register Uint32 anAttrSizeInWords, + register Uint32 anAttrBitsInLastWord) +{ + NdbApiSignal* tSignal; + NdbApiSignal* tCurrentKEYINFO; + //register NdbApiSignal* tTCREQ = theTCREQ; + register Uint32 tAttrPos; + Uint32 tPosition; + Uint32 tEndPos; + Uint32 tPos; + Uint32 signalCounter; + Uint32 tData; + +/***************************************************************************** + * Calculate the end position of the attribute in the key information. * + * Since the first attribute starts at position one we need to subtract * + * one to get the correct end position. * + * We must also remember the last word with only partial information. * + *****************************************************************************/ + tEndPos = aStartPosition + anAttrSizeInWords - 1; + + if ((tEndPos < 9) && (anAttrBitsInLastWord == 0)) { + register Uint32 tkeyData = *(Uint32*)aValue; + //TcKeyReq* tcKeyReq = CAST_PTR(TcKeyReq, tTCREQ->getDataPtrSend()); + register Uint32* tDataPtr = (Uint32*)aValue; + tAttrPos = 1; + register Uint32* tkeyDataPtr = theKEYINFOptr + aStartPosition - 1; + // (Uint32*)&tcKeyReq->keyInfo[aStartPosition - 1]; + do { + tDataPtr++; + *tkeyDataPtr = tkeyData; + if (tAttrPos < anAttrSizeInWords) { + ; + } else { + return 0; + }//if + tkeyData = *tDataPtr; + tkeyDataPtr++; + tAttrPos++; + } while (1); + return 0; + }//if +/***************************************************************************** + * Allocate all the KEYINFO signals needed for this key before starting * + * to fill the signals with data. This simplifies error handling and * + * avoids duplication of code. * + *****************************************************************************/ + tAttrPos = 0; + signalCounter = 1; + while(tEndPos > theTotalNrOfKeyWordInSignal) + { + tSignal = theNdb->getSignal(); + if (tSignal == NULL) + { + setErrorCodeAbort(4000); + return -1; + } + if (tSignal->setSignal(m_keyInfoGSN) == -1) + { + setErrorCodeAbort(4001); + return -1; + } + if (theFirstKEYINFO != NULL) + theLastKEYINFO->next(tSignal); + else + theFirstKEYINFO = tSignal; + theLastKEYINFO = tSignal; + theLastKEYINFO->next(NULL); + theTotalNrOfKeyWordInSignal += 20; + } + +/***************************************************************************** + * Change to variable tPosition for more appropriate naming of rest of * + * the code. We must set up current KEYINFO already here if the last * + * word is a word which is set at LastWordLabel and at the same time * + * this is the first word in a KEYINFO signal. * + *****************************************************************************/ + tPosition = aStartPosition; + tCurrentKEYINFO = theFirstKEYINFO; + +/***************************************************************************** + * Start by filling up Key information in the 8 words allocated in the * + * TC[KEY/INDX]REQ signal. * + *****************************************************************************/ + while (tPosition < 9) + { + theKEYINFOptr[tPosition-1] = * (Uint32*)(aValue + (tAttrPos << 2)); + tAttrPos++; + if (anAttrSizeInWords == tAttrPos) + goto LastWordLabel; + tPosition++; + } + +/***************************************************************************** + * We must set up the start position of the writing of Key information * + * before we start the writing of KEYINFO signals. If the start is not * + * the first word of the first KEYINFO signals then we must step forward* + * to the proper KEYINFO signal and set the signalCounter properly. * + * signalCounter is set to the actual position in the signal ( = 4 for * + * first key word in KEYINFO signal. * + *****************************************************************************/ + tPos = 8; + while ((tPosition - tPos) > 20) + { + tCurrentKEYINFO = tCurrentKEYINFO->next(); + tPos += 20; + } + signalCounter = tPosition - tPos + 3; + +/***************************************************************************** + * The loop that actually fills in the Key information into the KEYINFO * + * signals. Can be optimised by writing larger chunks than 4 bytes at a * + * time. * + *****************************************************************************/ + do + { + if (signalCounter > 23) + { + tCurrentKEYINFO = tCurrentKEYINFO->next(); + signalCounter = 4; + } + tCurrentKEYINFO->setData(*(Uint32*)(aValue + (tAttrPos << 2)), + signalCounter); + tAttrPos++; + if (anAttrSizeInWords == tAttrPos) + goto LastWordLabel; + tPosition++; + signalCounter++; + } while (1); + +LastWordLabel: + +/***************************************************************************** + * There could be a last word that only contains partial data. This word* + * will contain zeroes in the rest of the bits since the index expects * + * a certain number of words and do not care for parts of words. * + *****************************************************************************/ + if (anAttrBitsInLastWord != 0) { + tData = *(Uint32*)(aValue + (anAttrSizeInWords - 1) * 4); + tData = convertEndian(tData); + tData = tData & ((1 << anAttrBitsInLastWord) - 1); + tData = convertEndian(tData); + if (tPosition > 8) { + tCurrentKEYINFO->setData(tData, signalCounter); + signalCounter++; + } else { + theTCREQ->setData(tData, (12 + tPosition)); + }//if + }//if + + return 0; +} |