📄 ndbblob.cpp
字号:
/* 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 */#include <Ndb.hpp>#include <NdbDictionaryImpl.hpp>#include <NdbTransaction.hpp>#include <NdbOperation.hpp>#include <NdbIndexOperation.hpp>#include <NdbRecAttr.hpp>#include <NdbBlob.hpp>#include "NdbBlobImpl.hpp"#include <NdbScanOperation.hpp>/* * Reading index table directly (as a table) is faster but there are * bugs or limitations. Keep the code and make possible to choose. */static const bool g_ndb_blob_ok_to_read_index_table = false;// state (inline)inline voidNdbBlob::setState(State newState){ DBUG_ENTER("NdbBlob::setState"); DBUG_PRINT("info", ("this=%p newState=%u", this, newState)); theState = newState; DBUG_VOID_RETURN;}// define blob tableintNdbBlob::getBlobTableName(char* btname, Ndb* anNdb, const char* tableName, const char* columnName){ NdbTableImpl* t = anNdb->theDictionary->m_impl.getTable(tableName); if (t == NULL) return -1; NdbColumnImpl* c = t->getColumn(columnName); if (c == NULL) return -1; getBlobTableName(btname, t, c); return 0;}voidNdbBlob::getBlobTableName(char* btname, const NdbTableImpl* t, const NdbColumnImpl* c){ assert(t != 0 && c != 0 && c->getBlobType()); memset(btname, 0, NdbBlobImpl::BlobTableNameSize); sprintf(btname, "NDB$BLOB_%d_%d", (int)t->m_tableId, (int)c->m_attrId);}voidNdbBlob::getBlobTable(NdbTableImpl& bt, const NdbTableImpl* t, const NdbColumnImpl* c){ char btname[NdbBlobImpl::BlobTableNameSize]; getBlobTableName(btname, t, c); bt.setName(btname); bt.setLogging(t->getLogging()); bt.setFragmentType(t->getFragmentType()); { NdbDictionary::Column bc("PK"); bc.setType(NdbDictionary::Column::Unsigned); assert(t->m_keyLenInWords != 0); bc.setLength(t->m_keyLenInWords); bc.setPrimaryKey(true); bc.setDistributionKey(true); bt.addColumn(bc); } { NdbDictionary::Column bc("DIST"); bc.setType(NdbDictionary::Column::Unsigned); bc.setPrimaryKey(true); bc.setDistributionKey(true); bt.addColumn(bc); } { NdbDictionary::Column bc("PART"); bc.setType(NdbDictionary::Column::Unsigned); bc.setPrimaryKey(true); bc.setDistributionKey(false); bt.addColumn(bc); } { NdbDictionary::Column bc("DATA"); switch (c->m_type) { case NdbDictionary::Column::Blob: bc.setType(NdbDictionary::Column::Binary); break; case NdbDictionary::Column::Text: bc.setType(NdbDictionary::Column::Char); break; default: assert(false); break; } bc.setLength(c->getPartSize()); bt.addColumn(bc); }}// initializationNdbBlob::NdbBlob(Ndb*){ init();}voidNdbBlob::init(){ theState = Idle; theNdb = NULL; theNdbCon = NULL; theNdbOp = NULL; theTable = NULL; theAccessTable = NULL; theBlobTable = NULL; theColumn = NULL; theFillChar = 0; theInlineSize = 0; thePartSize = 0; theStripeSize = 0; theGetFlag = false; theGetBuf = NULL; theSetFlag = false; theSetBuf = NULL; theGetSetBytes = 0; thePendingBlobOps = 0; theActiveHook = NULL; theActiveHookArg = NULL; theHead = NULL; theInlineData = NULL; theHeadInlineRecAttr = NULL; theHeadInlineReadOp = NULL; theHeadInlineUpdateFlag = false; theNullFlag = -1; theLength = 0; thePos = 0; theNext = NULL;}voidNdbBlob::release(){ setState(Idle);}// buffersNdbBlob::Buf::Buf() : data(NULL), size(0), maxsize(0){}NdbBlob::Buf::~Buf(){ delete [] data;}voidNdbBlob::Buf::alloc(unsigned n){ size = n; if (maxsize < n) { delete [] data; // align to Uint64 if (n % 8 != 0) n += 8 - n % 8; data = new char [n]; maxsize = n; }#ifdef VM_TRACE memset(data, 'X', maxsize);#endif}voidNdbBlob::Buf::copyfrom(const NdbBlob::Buf& src){ assert(size == src.size); memcpy(data, src.data, size);}// classify operations (inline)inline boolNdbBlob::isTableOp(){ return theTable == theAccessTable;}inline boolNdbBlob::isIndexOp(){ return theTable != theAccessTable;}inline boolNdbBlob::isKeyOp(){ return theNdbOp->theOperationType == NdbOperation::InsertRequest || theNdbOp->theOperationType == NdbOperation::UpdateRequest || theNdbOp->theOperationType == NdbOperation::WriteRequest || theNdbOp->theOperationType == NdbOperation::ReadRequest || theNdbOp->theOperationType == NdbOperation::ReadExclusive || theNdbOp->theOperationType == NdbOperation::DeleteRequest;}inline boolNdbBlob::isReadOp(){ return theNdbOp->theOperationType == NdbOperation::ReadRequest || theNdbOp->theOperationType == NdbOperation::ReadExclusive;}inline boolNdbBlob::isInsertOp(){ return theNdbOp->theOperationType == NdbOperation::InsertRequest;}inline boolNdbBlob::isUpdateOp(){ return theNdbOp->theOperationType == NdbOperation::UpdateRequest;}inline boolNdbBlob::isWriteOp(){ return theNdbOp->theOperationType == NdbOperation::WriteRequest;}inline boolNdbBlob::isDeleteOp(){ return theNdbOp->theOperationType == NdbOperation::DeleteRequest;}inline boolNdbBlob::isScanOp(){ return theNdbOp->theOperationType == NdbOperation::OpenScanRequest || theNdbOp->theOperationType == NdbOperation::OpenRangeScanRequest;}// computations (inline)inline Uint32NdbBlob::getPartNumber(Uint64 pos){ assert(thePartSize != 0 && pos >= theInlineSize); return (pos - theInlineSize) / thePartSize;}inline Uint32NdbBlob::getPartCount(){ if (theLength <= theInlineSize) return 0; return 1 + getPartNumber(theLength - 1);}inline Uint32NdbBlob::getDistKey(Uint32 part){ assert(theStripeSize != 0); return (part / theStripeSize) % theStripeSize;}// getters and settersintNdbBlob::getTableKeyValue(NdbOperation* anOp){ DBUG_ENTER("NdbBlob::getTableKeyValue"); Uint32* data = (Uint32*)theKeyBuf.data; unsigned pos = 0; for (unsigned i = 0; i < theTable->m_columns.size(); i++) { NdbColumnImpl* c = theTable->m_columns[i]; assert(c != NULL); if (c->m_pk) { unsigned len = c->m_attrSize * c->m_arraySize; if (anOp->getValue_impl(c, (char*)&data[pos]) == NULL) { setErrorCode(anOp); DBUG_RETURN(-1); } // odd bytes receive no data and must be zeroed while (len % 4 != 0) { char* p = (char*)&data[pos] + len++; *p = 0; } pos += len / 4; } } assert(pos == theKeyBuf.size / 4); DBUG_RETURN(0);}intNdbBlob::setTableKeyValue(NdbOperation* anOp){ DBUG_ENTER("NdbBlob::setTableKeyValue"); DBUG_DUMP("info", theKeyBuf.data, 4 * theTable->m_keyLenInWords); const Uint32* data = (const Uint32*)theKeyBuf.data; const unsigned columns = theTable->m_columns.size(); unsigned pos = 0; for (unsigned i = 0; i < columns; i++) { NdbColumnImpl* c = theTable->m_columns[i]; assert(c != NULL); if (c->m_pk) { unsigned len = c->m_attrSize * c->m_arraySize; if (anOp->equal_impl(c, (const char*)&data[pos], len) == -1) { setErrorCode(anOp); DBUG_RETURN(-1); } pos += (len + 3) / 4; } } assert(pos == theKeyBuf.size / 4); DBUG_RETURN(0);}intNdbBlob::setAccessKeyValue(NdbOperation* anOp){ DBUG_ENTER("NdbBlob::setAccessKeyValue"); DBUG_DUMP("info", theAccessKeyBuf.data, 4 * theAccessTable->m_keyLenInWords); const Uint32* data = (const Uint32*)theAccessKeyBuf.data; const unsigned columns = theAccessTable->m_columns.size(); unsigned pos = 0; for (unsigned i = 0; i < columns; i++) { NdbColumnImpl* c = theAccessTable->m_columns[i]; assert(c != NULL); if (c->m_pk) { unsigned len = c->m_attrSize * c->m_arraySize; if (anOp->equal_impl(c, (const char*)&data[pos], len) == -1) { setErrorCode(anOp); DBUG_RETURN(-1); } pos += (len + 3) / 4; } } assert(pos == theAccessKeyBuf.size / 4); DBUG_RETURN(0);}intNdbBlob::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; // TODO use attr ids after compatibility with 4.1.7 not needed if (anOp->equal("PK", theKeyBuf.data) == -1 || anOp->equal("DIST", getDistKey(part)) == -1 || anOp->equal("PART", part) == -1) { setErrorCode(anOp); DBUG_RETURN(-1); } DBUG_RETURN(0);}intNdbBlob::getHeadInlineValue(NdbOperation* anOp){ DBUG_ENTER("NdbBlob::getHeadInlineValue"); theHeadInlineRecAttr = anOp->getValue_impl(theColumn, theHeadInlineBuf.data); if (theHeadInlineRecAttr == NULL) { setErrorCode(anOp); DBUG_RETURN(-1); } DBUG_RETURN(0);}voidNdbBlob::getHeadFromRecAttr(){ DBUG_ENTER("NdbBlob::getHeadFromRecAttr"); assert(theHeadInlineRecAttr != NULL); theNullFlag = theHeadInlineRecAttr->isNULL(); assert(theNullFlag != -1); theLength = ! theNullFlag ? theHead->length : 0; DBUG_VOID_RETURN;}intNdbBlob::setHeadInlineValue(NdbOperation* anOp){ DBUG_ENTER("NdbBlob::setHeadInlineValue"); theHead->length = theLength; if (theLength < theInlineSize) memset(theInlineData + theLength, 0, theInlineSize - theLength); assert(theNullFlag != -1); const char* aValue = theNullFlag ? 0 : theHeadInlineBuf.data; if (anOp->setValue(theColumn, aValue, theHeadInlineBuf.size) == -1) { setErrorCode(anOp); DBUG_RETURN(-1); } theHeadInlineUpdateFlag = false; DBUG_RETURN(0);}// getValue/setValueintNdbBlob::getValue(void* data, Uint32 bytes){ DBUG_ENTER("NdbBlob::getValue"); DBUG_PRINT("info", ("data=%p bytes=%u", data, bytes)); if (theGetFlag || theState != Prepared) { setErrorCode(NdbBlobImpl::ErrState); DBUG_RETURN(-1); } if (! isReadOp() && ! isScanOp()) { setErrorCode(NdbBlobImpl::ErrUsage); DBUG_RETURN(-1); } if (data == NULL && bytes != 0) { setErrorCode(NdbBlobImpl::ErrUsage); DBUG_RETURN(-1); } theGetFlag = true; theGetBuf = static_cast<char*>(data); theGetSetBytes = bytes; DBUG_RETURN(0);}intNdbBlob::setValue(const void* data, Uint32 bytes){ DBUG_ENTER("NdbBlob::setValue"); DBUG_PRINT("info", ("data=%p bytes=%u", data, bytes)); if (theSetFlag || theState != Prepared) { setErrorCode(NdbBlobImpl::ErrState); DBUG_RETURN(-1); } if (! isInsertOp() && ! isUpdateOp() && ! isWriteOp()) { setErrorCode(NdbBlobImpl::ErrUsage); DBUG_RETURN(-1); } if (data == NULL && bytes != 0) { setErrorCode(NdbBlobImpl::ErrUsage); DBUG_RETURN(-1); } theSetFlag = true; theSetBuf = static_cast<const char*>(data); theGetSetBytes = bytes; if (isInsertOp()) { // write inline part now if (theSetBuf != NULL) { Uint32 n = theGetSetBytes; if (n > theInlineSize) n = theInlineSize; assert(thePos == 0); if (writeDataPrivate(theSetBuf, n) == -1) DBUG_RETURN(-1); } else { theNullFlag = true; theLength = 0; } if (setHeadInlineValue(theNdbOp) == -1) DBUG_RETURN(-1); } DBUG_RETURN(0);}// activation hookintNdbBlob::setActiveHook(ActiveHook activeHook, void* arg){ DBUG_ENTER("NdbBlob::setActiveHook"); DBUG_PRINT("info", ("hook=%p arg=%p", (void*)activeHook, arg)); if (theState != Prepared) { setErrorCode(NdbBlobImpl::ErrState); DBUG_RETURN(-1); } theActiveHook = activeHook; theActiveHookArg = arg; DBUG_RETURN(0);}// misc operationsintNdbBlob::getNull(bool& isNull){ DBUG_ENTER("NdbBlob::getNull"); if (theState == Prepared && theSetFlag) { isNull = (theSetBuf == NULL); DBUG_RETURN(0); } if (theNullFlag == -1) { setErrorCode(NdbBlobImpl::ErrState); DBUG_RETURN(-1); } isNull = theNullFlag; DBUG_RETURN(0);}intNdbBlob::setNull(){ DBUG_ENTER("NdbBlob::setNull"); if (theNullFlag == -1) { if (theState == Prepared) { DBUG_RETURN(setValue(0, 0)); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -