Commit e9bfc415 authored by unknown's avatar unknown

ndb - bug#19285 : document and check what blob ops are allowed


ndb/src/ndbapi/ndberror.c:
  distinguish blob method errors: 4265-wrong state 4275-wrong op type/lockmode
ndb/src/ndbapi/NdbBlobImpl.hpp:
  distinguish blob method errors: 4265-wrong state 4275-wrong op type/lockmode
  fix 4269 -> 4270
ndb/test/ndbapi/testBlobs.cpp:
  test lock upgrade, test 4275 errors
ndb/include/ndbapi/NdbScanOperation.hpp:
  fix comment
ndb/include/ndbapi/NdbBlob.hpp:
  upgrade LM_CommittedRead to LM_Read
  check if write allowed (new error 4275)
  dont invalidate blob state on error (just general principle)
ndb/src/ndbapi/NdbBlob.cpp:
  upgrade LM_CommittedRead to LM_Read
  check if write allowed (new error 4275)
  dont invalidate blob state on error (just general principle)
parent 31ed3fd3
...@@ -74,19 +74,41 @@ class NdbColumnImpl; ...@@ -74,19 +74,41 @@ class NdbColumnImpl;
* NdbBlob methods return -1 on error and 0 on success, and use output * NdbBlob methods return -1 on error and 0 on success, and use output
* parameters when necessary. * parameters when necessary.
* *
* Operation types: * Usage notes for different operation types:
* - insertTuple must use setValue if blob column is non-nullable *
* - readTuple with exclusive lock can also update existing value * - insertTuple must use setValue if blob attribute is non-nullable
* - updateTuple can overwrite with setValue or update existing value *
* - writeTuple always overwrites and must use setValue if non-nullable * - readTuple or scan readTuples with lock mode LM_CommittedRead is
* automatically upgraded to lock mode LM_Read if any blob attributes
* are accessed (to guarantee consistent view)
*
* - readTuple (with any lock mode) can only read blob value
*
* - updateTuple can either overwrite existing value with setValue or
* update it in active phase
*
* - writeTuple always overwrites blob value and must use setValue if
* blob attribute is non-nullable
*
* - deleteTuple creates implicit non-accessible blob handles * - deleteTuple creates implicit non-accessible blob handles
* - scan with exclusive lock can also update existing value *
* - scan "lock takeover" update op must do its own getBlobHandle * - scan readTuples (any lock mode) can use its blob handles only
* to read blob value
*
* - scan readTuples with lock mode LM_Exclusive can update row and blob
* value using updateCurrentTuple, where the operation returned must
* create its own blob handles explicitly
*
* - scan readTuples with lock mode LM_Exclusive can delete row (and
* therefore blob values) using deleteCurrentTuple, which creates
* implicit non-accessible blob handles
*
* - the operation returned by lockCurrentTuple cannot update blob value
* *
* Bugs / limitations: * Bugs / limitations:
* - lock mode upgrade should be handled automatically *
* - lock mode vs allowed operation is not checked
* - too many pending blob ops can blow up i/o buffers * - too many pending blob ops can blow up i/o buffers
*
* - table and its blob part tables are not created atomically * - table and its blob part tables are not created atomically
*/ */
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
...@@ -194,6 +216,9 @@ public: ...@@ -194,6 +216,9 @@ public:
/** /**
* Return error object. The error may be blob specific (below) or may * Return error object. The error may be blob specific (below) or may
* be copied from a failed implicit operation. * be copied from a failed implicit operation.
*
* The error code is copied back to the operation unless the operation
* already has a non-zero error code.
*/ */
const NdbError& getNdbError() const; const NdbError& getNdbError() const;
/** /**
...@@ -290,6 +315,7 @@ private: ...@@ -290,6 +315,7 @@ private:
bool isWriteOp(); bool isWriteOp();
bool isDeleteOp(); bool isDeleteOp();
bool isScanOp(); bool isScanOp();
bool isReadOnlyOp();
bool isTakeOverOp(); bool isTakeOverOp();
// computations // computations
Uint32 getPartNumber(Uint64 pos); Uint32 getPartNumber(Uint64 pos);
...@@ -323,9 +349,9 @@ private: ...@@ -323,9 +349,9 @@ private:
int preCommit(); int preCommit();
int atNextResult(); int atNextResult();
// errors // errors
void setErrorCode(int anErrorCode, bool invalidFlag = true); void setErrorCode(int anErrorCode, bool invalidFlag = false);
void setErrorCode(NdbOperation* anOp, bool invalidFlag = true); void setErrorCode(NdbOperation* anOp, bool invalidFlag = false);
void setErrorCode(NdbTransaction* aCon, bool invalidFlag = true); void setErrorCode(NdbTransaction* aCon, bool invalidFlag = false);
#ifdef VM_TRACE #ifdef VM_TRACE
int getOperationType() const; int getOperationType() const;
friend class NdbOut& operator<<(NdbOut&, const NdbBlob&); friend class NdbOut& operator<<(NdbOut&, const NdbBlob&);
......
...@@ -41,7 +41,7 @@ public: ...@@ -41,7 +41,7 @@ public:
* readTuples. * readTuples.
*/ */
enum ScanFlag { enum ScanFlag {
SF_TupScan = (1 << 16), // scan TUP - only LM_CommittedRead SF_TupScan = (1 << 16), // scan TUP
SF_OrderBy = (1 << 24), // index scan in order SF_OrderBy = (1 << 24), // index scan in order
SF_Descending = (2 << 24), // index scan in descending order SF_Descending = (2 << 24), // index scan in descending order
SF_ReadRangeNo = (4 << 24), // enable @ref get_range_no SF_ReadRangeNo = (4 << 24), // enable @ref get_range_no
......
...@@ -265,6 +265,16 @@ NdbBlob::isScanOp() ...@@ -265,6 +265,16 @@ NdbBlob::isScanOp()
theNdbOp->theOperationType == NdbOperation::OpenRangeScanRequest; theNdbOp->theOperationType == NdbOperation::OpenRangeScanRequest;
} }
inline bool
NdbBlob::isReadOnlyOp()
{
return ! (
theNdbOp->theOperationType == NdbOperation::InsertRequest ||
theNdbOp->theOperationType == NdbOperation::UpdateRequest ||
theNdbOp->theOperationType == NdbOperation::WriteRequest
);
}
inline bool inline bool
NdbBlob::isTakeOverOp() NdbBlob::isTakeOverOp()
{ {
...@@ -438,12 +448,12 @@ NdbBlob::getValue(void* data, Uint32 bytes) ...@@ -438,12 +448,12 @@ NdbBlob::getValue(void* data, Uint32 bytes)
{ {
DBUG_ENTER("NdbBlob::getValue"); DBUG_ENTER("NdbBlob::getValue");
DBUG_PRINT("info", ("data=%p bytes=%u", data, bytes)); DBUG_PRINT("info", ("data=%p bytes=%u", data, bytes));
if (theGetFlag || theState != Prepared) { if (! isReadOp() && ! isScanOp()) {
setErrorCode(NdbBlobImpl::ErrState); setErrorCode(NdbBlobImpl::ErrCompat);
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
if (! isReadOp() && ! isScanOp()) { if (theGetFlag || theState != Prepared) {
setErrorCode(NdbBlobImpl::ErrUsage); setErrorCode(NdbBlobImpl::ErrState);
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
if (data == NULL && bytes != 0) { if (data == NULL && bytes != 0) {
...@@ -461,12 +471,12 @@ NdbBlob::setValue(const void* data, Uint32 bytes) ...@@ -461,12 +471,12 @@ NdbBlob::setValue(const void* data, Uint32 bytes)
{ {
DBUG_ENTER("NdbBlob::setValue"); DBUG_ENTER("NdbBlob::setValue");
DBUG_PRINT("info", ("data=%p bytes=%u", data, bytes)); DBUG_PRINT("info", ("data=%p bytes=%u", data, bytes));
if (theSetFlag || theState != Prepared) { if (isReadOnlyOp()) {
setErrorCode(NdbBlobImpl::ErrState); setErrorCode(NdbBlobImpl::ErrCompat);
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
if (! isInsertOp() && ! isUpdateOp() && ! isWriteOp()) { if (theSetFlag || theState != Prepared) {
setErrorCode(NdbBlobImpl::ErrUsage); setErrorCode(NdbBlobImpl::ErrState);
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
if (data == NULL && bytes != 0) { if (data == NULL && bytes != 0) {
...@@ -533,6 +543,10 @@ int ...@@ -533,6 +543,10 @@ int
NdbBlob::setNull() NdbBlob::setNull()
{ {
DBUG_ENTER("NdbBlob::setNull"); DBUG_ENTER("NdbBlob::setNull");
if (isReadOnlyOp()) {
setErrorCode(NdbBlobImpl::ErrCompat);
DBUG_RETURN(-1);
}
if (theNullFlag == -1) { if (theNullFlag == -1) {
if (theState == Prepared) { if (theState == Prepared) {
DBUG_RETURN(setValue(0, 0)); DBUG_RETURN(setValue(0, 0));
...@@ -571,6 +585,10 @@ NdbBlob::truncate(Uint64 length) ...@@ -571,6 +585,10 @@ NdbBlob::truncate(Uint64 length)
{ {
DBUG_ENTER("NdbBlob::truncate"); DBUG_ENTER("NdbBlob::truncate");
DBUG_PRINT("info", ("length=%llu", length)); DBUG_PRINT("info", ("length=%llu", length));
if (isReadOnlyOp()) {
setErrorCode(NdbBlobImpl::ErrCompat);
DBUG_RETURN(-1);
}
if (theNullFlag == -1) { if (theNullFlag == -1) {
setErrorCode(NdbBlobImpl::ErrState); setErrorCode(NdbBlobImpl::ErrState);
DBUG_RETURN(-1); DBUG_RETURN(-1);
...@@ -628,12 +646,14 @@ NdbBlob::setPos(Uint64 pos) ...@@ -628,12 +646,14 @@ NdbBlob::setPos(Uint64 pos)
int int
NdbBlob::readData(void* data, Uint32& bytes) NdbBlob::readData(void* data, Uint32& bytes)
{ {
DBUG_ENTER("NdbBlob::readData");
if (theState != Active) { if (theState != Active) {
setErrorCode(NdbBlobImpl::ErrState); setErrorCode(NdbBlobImpl::ErrState);
return -1; DBUG_RETURN(-1);
} }
char* buf = static_cast<char*>(data); char* buf = static_cast<char*>(data);
return readDataPrivate(buf, bytes); int ret = readDataPrivate(buf, bytes);
DBUG_RETURN(ret);
} }
int int
...@@ -722,12 +742,18 @@ NdbBlob::readDataPrivate(char* buf, Uint32& bytes) ...@@ -722,12 +742,18 @@ NdbBlob::readDataPrivate(char* buf, Uint32& bytes)
int int
NdbBlob::writeData(const void* data, Uint32 bytes) NdbBlob::writeData(const void* data, Uint32 bytes)
{ {
DBUG_ENTER("NdbBlob::writeData");
if (isReadOnlyOp()) {
setErrorCode(NdbBlobImpl::ErrCompat);
DBUG_RETURN(-1);
}
if (theState != Active) { if (theState != Active) {
setErrorCode(NdbBlobImpl::ErrState); setErrorCode(NdbBlobImpl::ErrState);
return -1; DBUG_RETURN(-1);
} }
const char* buf = static_cast<const char*>(data); const char* buf = static_cast<const char*>(data);
return writeDataPrivate(buf, bytes); int ret = writeDataPrivate(buf, bytes);
DBUG_RETURN(0);
} }
int int
...@@ -1130,6 +1156,9 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl ...@@ -1130,6 +1156,9 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl
} }
} }
if (isReadOp()) { if (isReadOp()) {
// upgrade lock mode
if (theNdbOp->theLockMode == NdbOperation::LM_CommittedRead)
theNdbOp->theLockMode = NdbOperation::LM_Read;
// add read of head+inline in this op // add read of head+inline in this op
if (getHeadInlineValue(theNdbOp) == -1) if (getHeadInlineValue(theNdbOp) == -1)
DBUG_RETURN(-1); DBUG_RETURN(-1);
...@@ -1148,6 +1177,9 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl ...@@ -1148,6 +1177,9 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl
supportedOp = true; supportedOp = true;
} }
if (isScanOp()) { if (isScanOp()) {
// upgrade lock mode
if (theNdbOp->theLockMode == NdbOperation::LM_CommittedRead)
theNdbOp->theLockMode = NdbOperation::LM_Read;
// add read of head+inline in this op // add read of head+inline in this op
if (getHeadInlineValue(theNdbOp) == -1) if (getHeadInlineValue(theNdbOp) == -1)
DBUG_RETURN(-1); DBUG_RETURN(-1);
......
...@@ -24,7 +24,7 @@ public: ...@@ -24,7 +24,7 @@ public:
STATIC_CONST( ErrTable = 4263 ); STATIC_CONST( ErrTable = 4263 );
// "Invalid usage of blob attribute" // "Invalid usage of blob attribute"
STATIC_CONST( ErrUsage = 4264 ); STATIC_CONST( ErrUsage = 4264 );
// "Method is not valid in current blob state" // "The blob method is not valid in current blob state"
STATIC_CONST( ErrState = 4265 ); STATIC_CONST( ErrState = 4265 );
// "Invalid blob seek position" // "Invalid blob seek position"
STATIC_CONST( ErrSeek = 4266 ); STATIC_CONST( ErrSeek = 4266 );
...@@ -33,7 +33,9 @@ public: ...@@ -33,7 +33,9 @@ public:
// "Error in blob head update forced rollback of transaction" // "Error in blob head update forced rollback of transaction"
STATIC_CONST( ErrAbort = 4268 ); STATIC_CONST( ErrAbort = 4268 );
// "Unknown blob error" // "Unknown blob error"
STATIC_CONST( ErrUnknown = 4269 ); STATIC_CONST( ErrUnknown = 4270 );
// "The blob method is incompatible with operation type or lock mode"
STATIC_CONST( ErrCompat = 4275 );
}; };
#endif #endif
...@@ -513,14 +513,15 @@ ErrorBundle ErrorCodes[] = { ...@@ -513,14 +513,15 @@ ErrorBundle ErrorCodes[] = {
{ 4262, UD, "NdbScanFilter: Condition is out of bounds"}, { 4262, UD, "NdbScanFilter: Condition is out of bounds"},
{ 4263, IE, "Invalid blob attributes or invalid blob parts table" }, { 4263, IE, "Invalid blob attributes or invalid blob parts table" },
{ 4264, AE, "Invalid usage of blob attribute" }, { 4264, AE, "Invalid usage of blob attribute" },
{ 4265, AE, "Method is not valid in current blob state" }, { 4265, AE, "The blob method is not valid in current blob state" },
{ 4266, AE, "Invalid blob seek position" }, { 4266, AE, "Invalid blob seek position" },
{ 4267, IE, "Corrupted blob value" }, { 4267, IE, "Corrupted blob value" },
{ 4268, IE, "Error in blob head update forced rollback of transaction" }, { 4268, IE, "Error in blob head update forced rollback of transaction" },
{ 4269, IE, "No connection to ndb management server" }, { 4269, IE, "No connection to ndb management server" },
{ 4270, IE, "Unknown blob error" }, { 4270, IE, "Unknown blob error" },
{ 4335, AE, "Only one autoincrement column allowed per table. Having a table without primary key uses an autoincremented hidden key, i.e. a table without a primary key can not have an autoincremented column" }, { 4335, AE, "Only one autoincrement column allowed per table. Having a table without primary key uses an autoincremented hidden key, i.e. a table without a primary key can not have an autoincremented column" },
{ 4271, AE, "Invalid index object, not retrieved via getIndex()" } { 4271, AE, "Invalid index object, not retrieved via getIndex()" },
{ 4275, IE, "The blob method is incompatible with operation type or lock mode" }
}; };
static static
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment