diff --git a/storage/ndb/include/ndbapi/NdbBlob.hpp b/storage/ndb/include/ndbapi/NdbBlob.hpp index 92265b4feef36031532e0fad873e33b8b1a87b38..9ae0ba6f02369ad2a44df11603f2f8580c7bfbfe 100644 --- a/storage/ndb/include/ndbapi/NdbBlob.hpp +++ b/storage/ndb/include/ndbapi/NdbBlob.hpp @@ -292,6 +292,7 @@ private: }; Buf theKeyBuf; Buf theAccessKeyBuf; + Buf thePackKeyBuf; Buf theHeadInlineBuf; Buf theHeadInlineCopyBuf; // for writeTuple Buf thePartBuf; @@ -328,6 +329,9 @@ private: Uint32 getPartNumber(Uint64 pos); Uint32 getPartCount(); Uint32 getDistKey(Uint32 part); + // pack / unpack + int packKeyValue(const NdbTableImpl* aTable, const Buf& srcBuf); + int unpackKeyValue(const NdbTableImpl* aTable, Buf& dstBuf); // getters and setters int getTableKeyValue(NdbOperation* anOp); int setTableKeyValue(NdbOperation* anOp); diff --git a/storage/ndb/include/ndbapi/NdbOperation.hpp b/storage/ndb/include/ndbapi/NdbOperation.hpp index c403b2c3438f706922ccf592a4985af5cee79090..3a442c94253a5f467190fb24546863f330333268 100644 --- a/storage/ndb/include/ndbapi/NdbOperation.hpp +++ b/storage/ndb/include/ndbapi/NdbOperation.hpp @@ -881,7 +881,7 @@ protected: Uint32 ptr2int() { return theReceiver.getId(); }; // get table or index key from prepared signals - int getKeyFromTCREQ(Uint32* data, unsigned size); + int getKeyFromTCREQ(Uint32* data, Uint32 & size); /****************************************************************************** * These are the private variables that are defined in the operation objects. diff --git a/storage/ndb/include/ndbapi/NdbScanOperation.hpp b/storage/ndb/include/ndbapi/NdbScanOperation.hpp index 103eabbe1a22f09bf0b3f3007627a4a24ff66acc..048e7a0c9523767fce154461b25720b8e4cf1d88 100644 --- a/storage/ndb/include/ndbapi/NdbScanOperation.hpp +++ b/storage/ndb/include/ndbapi/NdbScanOperation.hpp @@ -240,7 +240,7 @@ protected: void receiver_completed(NdbReceiver*); void execCLOSE_SCAN_REP(); - int getKeyFromKEYINFO20(Uint32* data, unsigned size); + int getKeyFromKEYINFO20(Uint32* data, Uint32 & size); NdbOperation* takeOverScanOp(OperationType opType, NdbTransaction*); bool m_ordered; diff --git a/storage/ndb/src/ndbapi/NdbBlob.cpp b/storage/ndb/src/ndbapi/NdbBlob.cpp index 663d346c8efdd255be27c4051a6f27497c61bc2b..680f9e5c70eba1865d99be39f2766b0c51877f24 100644 --- a/storage/ndb/src/ndbapi/NdbBlob.cpp +++ b/storage/ndb/src/ndbapi/NdbBlob.cpp @@ -310,7 +310,7 @@ NdbBlob::Buf::alloc(unsigned n) void NdbBlob::Buf::copyfrom(const NdbBlob::Buf& src) { - assert(size == src.size); + size = src.size; memcpy(data, src.data, size); } @@ -408,6 +408,75 @@ NdbBlob::getDistKey(Uint32 part) return (part / theStripeSize) % theStripeSize; } +// pack/unpack table/index key XXX support routines, shortcuts + +int +NdbBlob::packKeyValue(const NdbTableImpl* aTable, const Buf& srcBuf) +{ + DBUG_ENTER("NdbBlob::packKeyValue"); + const Uint32* data = (const Uint32*)srcBuf.data; + unsigned pos = 0; + Uint32* pack_data = (Uint32*)thePackKeyBuf.data; + unsigned pack_pos = 0; + for (unsigned i = 0; i < aTable->m_columns.size(); i++) { + NdbColumnImpl* c = aTable->m_columns[i]; + assert(c != NULL); + if (c->m_pk) { + unsigned len = c->m_attrSize * c->m_arraySize; + Uint32 pack_len; + bool ok = c->get_var_length(&data[pos], pack_len); + if (! ok) { + setErrorCode(NdbBlobImpl::ErrCorruptPK); + DBUG_RETURN(-1); + } + memcpy(&pack_data[pack_pos], &data[pos], pack_len); + while (pack_len % 4 != 0) { + char* p = (char*)&pack_data[pack_pos] + pack_len++; + *p = 0; + } + pos += (len + 3) / 4; + pack_pos += pack_len / 4; + } + } + assert(4 * pos == srcBuf.size); + assert(4 * pack_pos <= thePackKeyBuf.maxsize); + thePackKeyBuf.size = 4 * pack_pos; + DBUG_RETURN(0); +} + +int +NdbBlob::unpackKeyValue(const NdbTableImpl* aTable, Buf& dstBuf) +{ + DBUG_ENTER("NdbBlob::unpackKeyValue"); + Uint32* data = (Uint32*)dstBuf.data; + unsigned pos = 0; + const Uint32* pack_data = (const Uint32*)thePackKeyBuf.data; + unsigned pack_pos = 0; + for (unsigned i = 0; i < aTable->m_columns.size(); i++) { + NdbColumnImpl* c = aTable->m_columns[i]; + assert(c != NULL); + if (c->m_pk) { + unsigned len = c->m_attrSize * c->m_arraySize; + Uint32 pack_len; + bool ok = c->get_var_length(&pack_data[pack_pos], pack_len); + if (! ok) { + setErrorCode(NdbBlobImpl::ErrCorruptPK); + DBUG_RETURN(-1); + } + memcpy(&data[pos], &pack_data[pack_pos], pack_len); + while (pack_len % 4 != 0) { + char* p = (char*)&data[pos] + pack_len++; + *p = 0; + } + pos += (len + 3) / 4; + pack_pos += pack_len / 4; + } + } + assert(4 * pos == dstBuf.size); + assert(4 * pack_pos == thePackKeyBuf.size); + DBUG_RETURN(0); +} + // getters and setters int @@ -489,12 +558,10 @@ int NdbBlob::setPartKeyValue(NdbOperation* anOp, Uint32 part) { DBUG_ENTER("NdbBlob::setPartKeyValue"); - DBUG_PRINT("info", ("dist=%u part=%u key=", getDistKey(part), part)); - DBUG_DUMP("info", theKeyBuf.data, 4 * theTable->m_keyLenInWords); - //Uint32* data = (Uint32*)theKeyBuf.data; - //unsigned size = theTable->m_keyLenInWords; + DBUG_PRINT("info", ("dist=%u part=%u packkey=", getDistKey(part), part)); + DBUG_DUMP("info", thePackKeyBuf.data, 4 * thePackKeyBuf.size); // TODO use attr ids after compatibility with 4.1.7 not needed - if (anOp->equal("PK", theKeyBuf.data) == -1 || + if (anOp->equal("PK", thePackKeyBuf.data) == -1 || anOp->equal("DIST", getDistKey(part)) == -1 || anOp->equal("PART", part) == -1) { setErrorCode(anOp); @@ -1242,21 +1309,27 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl if (isKeyOp()) { if (isTableOp()) { // get table key - Uint32* data = (Uint32*)theKeyBuf.data; - unsigned size = theTable->m_keyLenInWords; + Uint32* data = (Uint32*)thePackKeyBuf.data; + Uint32 size = theTable->m_keyLenInWords; // in-out if (theNdbOp->getKeyFromTCREQ(data, size) == -1) { setErrorCode(NdbBlobImpl::ErrUsage); DBUG_RETURN(-1); } + thePackKeyBuf.size = 4 * size; + if (unpackKeyValue(theTable, theKeyBuf) == -1) + DBUG_RETURN(-1); } if (isIndexOp()) { // get index key - Uint32* data = (Uint32*)theAccessKeyBuf.data; - unsigned size = theAccessTable->m_keyLenInWords; + Uint32* data = (Uint32*)thePackKeyBuf.data; + Uint32 size = theAccessTable->m_keyLenInWords; // in-out if (theNdbOp->getKeyFromTCREQ(data, size) == -1) { setErrorCode(NdbBlobImpl::ErrUsage); DBUG_RETURN(-1); } + thePackKeyBuf.size = 4 * size; + if (unpackKeyValue(theAccessTable, theAccessKeyBuf) == -1) + DBUG_RETURN(-1); } if (isReadOp()) { // add read of head+inline in this op @@ -1303,6 +1376,7 @@ NdbBlob::atPrepare(NdbEventOperationImpl* anOp, NdbEventOperationImpl* aBlobOp, theEventOp = anOp; theBlobEventOp = aBlobOp; theTable = anOp->m_eventImpl->m_tableImpl; + theAccessTable = theTable; theColumn = aColumn; // prepare blob column and table if (prepareColumn() == -1) @@ -1321,7 +1395,7 @@ NdbBlob::atPrepare(NdbEventOperationImpl* anOp, NdbEventOperationImpl* aBlobOp, if (theBlobEventOp != NULL) { if ((theBlobEventPkRecAttr = theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)0), - theKeyBuf.data, version)) == NULL || + thePackKeyBuf.data, version)) == NULL || (theBlobEventDistRecAttr = theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)1), (char*)0, version)) == NULL || @@ -1380,6 +1454,7 @@ NdbBlob::prepareColumn() } // these buffers are always used theKeyBuf.alloc(theTable->m_keyLenInWords << 2); + thePackKeyBuf.alloc(max(theTable->m_keyLenInWords, theAccessTable->m_keyLenInWords) << 2); theHeadInlineBuf.alloc(sizeof(Head) + theInlineSize); theHead = (Head*)theHeadInlineBuf.data; theInlineData = theHeadInlineBuf.data + sizeof(Head); @@ -1464,7 +1539,7 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch) if (tOp == NULL || tOp->readTuple() == -1 || setAccessKeyValue(tOp) == -1 || - tOp->getValue(pkAttrId, theKeyBuf.data) == NULL) { + tOp->getValue(pkAttrId, thePackKeyBuf.data) == NULL) { setErrorCode(tOp); DBUG_RETURN(-1); } @@ -1553,10 +1628,12 @@ NdbBlob::postExecute(NdbTransaction::ExecType anExecType) assert(isKeyOp()); if (isIndexOp()) { NdbBlob* tFirstBlob = theNdbOp->theBlobList; - if (this != tFirstBlob) { + if (this == tFirstBlob) { + packKeyValue(theTable, theKeyBuf); + } else { // copy key from first blob - assert(theKeyBuf.size == tFirstBlob->theKeyBuf.size); - memcpy(theKeyBuf.data, tFirstBlob->theKeyBuf.data, tFirstBlob->theKeyBuf.size); + theKeyBuf.copyfrom(tFirstBlob->theKeyBuf); + thePackKeyBuf.copyfrom(tFirstBlob->thePackKeyBuf); } } if (isReadOp()) { @@ -1710,12 +1787,16 @@ NdbBlob::atNextResult() DBUG_RETURN(-1); assert(isScanOp()); // get primary key - { Uint32* data = (Uint32*)theKeyBuf.data; - unsigned size = theTable->m_keyLenInWords; - if (((NdbScanOperation*)theNdbOp)->getKeyFromKEYINFO20(data, size) == -1) { + { NdbScanOperation* tScanOp = (NdbScanOperation*)theNdbOp; + Uint32* data = (Uint32*)thePackKeyBuf.data; + unsigned size = theTable->m_keyLenInWords; // in-out + if (tScanOp->getKeyFromKEYINFO20(data, size) == -1) { setErrorCode(NdbBlobImpl::ErrUsage); DBUG_RETURN(-1); } + thePackKeyBuf.size = 4 * size; + if (unpackKeyValue(theTable, theKeyBuf) == -1) + DBUG_RETURN(-1); } getHeadFromRecAttr(); if (setPos(0) == -1) diff --git a/storage/ndb/src/ndbapi/NdbBlobImpl.hpp b/storage/ndb/src/ndbapi/NdbBlobImpl.hpp index 0030e910c52ed6b5a64ccc24f59eb910595b7f92..e6b41c964e64ff9034ac4be7c31dc254466982f4 100644 --- a/storage/ndb/src/ndbapi/NdbBlobImpl.hpp +++ b/storage/ndb/src/ndbapi/NdbBlobImpl.hpp @@ -34,6 +34,8 @@ public: STATIC_CONST( ErrAbort = 4268 ); // "Unknown blob error" STATIC_CONST( ErrUnknown = 4269 ); + // "Corrupted main table PK in blob operation" + STATIC_CONST( ErrCorruptPK = 4274 ); }; #endif diff --git a/storage/ndb/src/ndbapi/NdbOperationSearch.cpp b/storage/ndb/src/ndbapi/NdbOperationSearch.cpp index f2d0d1079a0d9ce022219fa52f1b2b1c5ad7146f..cea8eff94122f2966944eb5f22e0d6244e776eb4 100644 --- a/storage/ndb/src/ndbapi/NdbOperationSearch.cpp +++ b/storage/ndb/src/ndbapi/NdbOperationSearch.cpp @@ -472,7 +472,8 @@ void NdbOperation::reorderKEYINFO() { Uint32 data[4000]; - getKeyFromTCREQ(data, 4000); + Uint32 size = 4000; + getKeyFromTCREQ(data, size); Uint32 pos = 1; Uint32 k; for (k = 0; k < m_accessTable->m_noOfKeys; k++) { @@ -501,7 +502,7 @@ NdbOperation::reorderKEYINFO() } int -NdbOperation::getKeyFromTCREQ(Uint32* data, unsigned size) +NdbOperation::getKeyFromTCREQ(Uint32* data, Uint32 & size) { assert(size >= theTupKeyLen && theTupKeyLen > 0); size = theTupKeyLen; diff --git a/storage/ndb/src/ndbapi/NdbRecAttr.cpp b/storage/ndb/src/ndbapi/NdbRecAttr.cpp index a03dd6c536f44bda6b740206cdcc033ee4b0b250..5931a00fcf7998fc057f4b0a042df4084e18b2fe 100644 --- a/storage/ndb/src/ndbapi/NdbRecAttr.cpp +++ b/storage/ndb/src/ndbapi/NdbRecAttr.cpp @@ -199,7 +199,7 @@ NdbOut& operator<<(NdbOut& out, const NdbRecAttr &r) out << hex << "H'" << r.u_32_value() << dec; break; case NdbDictionary::Column::Unsigned: - out << r.u_32_value(); + out << *((Uint32*)r.aRef() + j); break; case NdbDictionary::Column::Smallunsigned: out << r.u_short_value(); diff --git a/storage/ndb/src/ndbapi/NdbScanOperation.cpp b/storage/ndb/src/ndbapi/NdbScanOperation.cpp index 9e6ff352987c3688c2b3a2a81a5923b37c3a8d3e..08cd275d4a887e93f856ab62f229bb480a0bb0cd 100644 --- a/storage/ndb/src/ndbapi/NdbScanOperation.cpp +++ b/storage/ndb/src/ndbapi/NdbScanOperation.cpp @@ -912,13 +912,20 @@ NdbScanOperation::doSendScan(int aProcessorId) * the scan process. ****************************************************************************/ int -NdbScanOperation::getKeyFromKEYINFO20(Uint32* data, unsigned size) +NdbScanOperation::getKeyFromKEYINFO20(Uint32* data, Uint32 & size) { NdbRecAttr * tRecAttr = m_curr_row; if(tRecAttr) { const Uint32 * src = (Uint32*)tRecAttr->aRef(); - memcpy(data, src, 4*size); + + assert(tRecAttr->get_size_in_bytes() > 0); + assert(tRecAttr->get_size_in_bytes() < 65536); + const Uint32 len = (tRecAttr->get_size_in_bytes() + 3)/4-1; + + assert(size >= len); + memcpy(data, src, 4*len); + size = len; return 0; } return -1; diff --git a/storage/ndb/src/ndbapi/ndberror.c b/storage/ndb/src/ndbapi/ndberror.c index bb4616a9ee2895823a6822a9dc935e17adabbe6c..9bc9fd4242e76a023a591043557fe44af0ed56cf 100644 --- a/storage/ndb/src/ndbapi/ndberror.c +++ b/storage/ndb/src/ndbapi/ndberror.c @@ -599,7 +599,8 @@ ErrorBundle ErrorCodes[] = { { 4336, DMEC, AE, "Auto-increment value set below current value" }, { 4271, DMEC, AE, "Invalid index object, not retrieved via getIndex()" }, { 4272, DMEC, AE, "Table definition has undefined column" }, - { 4273, DMEC, IE, "No blob table in dict cache" } + { 4273, DMEC, IE, "No blob table in dict cache" }, + { 4274, DMEC, IE, "Corrupted main table PK in blob operation" } }; static diff --git a/storage/ndb/test/ndbapi/testBlobs.cpp b/storage/ndb/test/ndbapi/testBlobs.cpp index fff5ac247dfdc06880ea19423409673ccc7cffa0..a1b0c89652e29948e34490cf437751ae7b21e11e 100644 --- a/storage/ndb/test/ndbapi/testBlobs.cpp +++ b/storage/ndb/test/ndbapi/testBlobs.cpp @@ -223,7 +223,7 @@ dropTable() { NdbDictionary::Table tab(g_opt.m_tname); if (g_dic->getTable(g_opt.m_tname) != 0) - CHK(g_dic->dropTable(tab) == 0); + CHK(g_dic->dropTable(g_opt.m_tname) == 0); return 0; }