Abstract
This section describes how NDB API errors can be detected and mapped onto particular operations.
NDB API errors can be generated in either of two ways:
When an operation is defined
When an operation is executed
Errors raised during operation definition.
Errors generated during operation definition result in a
failure return code from the method called. The actual error
can be determined by examining the relevant
NdbOperation
object, or the
operation's NdbTransaction
object.
Errors raised during operation execution.
Errors occurring during operation execution cause the
transaction of which they are a part to be aborted unless the
AO_IgnoreError
abort option is set for the
operation.
If you have worked with older versions of the NDB API, you
should be aware that, beginning with MySQL Cluster NDB
6.2.0, the AbortOption
type is a member
of NdbOperation
. See
Section 2.3.15.1.1, “The NdbOperation::AbortOption
Type”, for more
information.
By default, read operations are run with
AO_IgnoreError
, and write operations are
run with AbortOnError
, but this can be
overridden by the user. When an error during execution causes
a transaction to be aborted, the execute()
method returns a failure return code. If an error is ignored
due to AO_IgnoreError
being set on the
operation, the execute()
method returns a
success code, and the user must examine all operations for
failure using NdbOperation::getNdbError()
.
For this reason, the return value of
getNdbError()
should usually be checked,
even if execute()
returns success. If the
client application does not keep track of
NdbOperation
objects during execution, then
NdbTransaction::getNextCompletedOperation()
can be used to iterate over them.
You should also be aware that use of NdbBlob
can result in extra operations being added to the batches
executed. This means that, when iterating over completed
operations using getNextCompletedOperation()
,
you may encounter operations related to
NdbBlob
objects which were not defined by
your application.
A read whose LockMode
is
CommittedRead
cannot be
AbortOnError
. In this case, it is always be
IgnoreError
.
In all cases where operation-specific errors arise, an execution
error with an operation is marked against both the operation and
the associated transaction object. Where there are multiple
operation errors in a single
NdbTransaction::execute()
call, due to
operation batching and the use of
AO_IgnoreError
, only the first is marked
against the NdbTransaction
object. The
remaining errors are recorded against the corresponding
NdbOperation
objects only.
It is also possible for errors to occur during execution — such as a data node failure — which are marked against the transaction object, but not against the underlying operation objects. This is because these errors apply to the transaction as a whole, and not to individual operations within the transaction.
For this reason, applications should use
NdbTransaction::getNdbError()
as the first
way to determine whether an
NdbTransaction::execute()
call failed. If the
batch of operations being executed included operations with the
AO_IgnoreError
abort option set, then it is
possible that there were multiple failures, and the completed
operations should be checked individually for errors using
NdbOperation::getNdbError()
.
Implicit NdbTransaction::execute()
calls in scan and
BLOB
methods.
Scan operations are executed in the same way as other
operations, and also have implicit
execute()
calls within the
NdbScanOperation::nextResult()
method. When
NdbScanOperation::nextResult()
indicates
failure (that is, if the method returns
-1
), the transaction object should be
checked for an error. The NdbScanOperation
may also contain the error, but only if the error is not
operation-specific.
Some BLOB
manipulation methods also have
implicit internal execute()
calls, and so can
experience operation execution failures at these points. The
following NdbBlob
methods can generate
implicit execute()
calls; this means that
they also require checks of the
NdbTransaction
object for errors via
NdbTransaction::getNdbError()
if they return
an error code:
setNull()
truncate()
readData()
writeData()
Summary. In general, it is possible for an error to occur during execution (resulting in a failure return code) when calling any of the following methods:
NdbTransaction::execute()
NdbBlob::setNull()
NdbBlob::truncate()
NdbBlob::readData()
NdbBlob::writeData()
NdbScanOperation::nextResult()
This method does not perform an
implicit execute()
call. The
NdbBlob
methods can cause other
defined operations to be executed when these methods
are called; however, nextResult()
calls do not do so.
If this happens, the
NdbTransaction::getNdbError()
method should
be called to identify the first error that occurred. When
operations are batched, and there are
IgnoreError
operations in the batch, there
may be multiple operations with errors in the transaction.
These can be found by using
NdbTransaction::getNextCompletedOperation()
to iterate over the set of completed operations, calling
NdbOperation::getNdbError()
for each
operation.
When IgnoreError
has been set on any
operations in a batch of operations to be executed, the
NdbTransaction::execute()
method indicates
success even where errors have actually occurred, as long as
none of these errors caused a transaction to be aborted. To
determine whether there were any ignored errors, the transaction
error status should be checked using
NdbTransaction::getNdbError()
. Only
if this indicates success can you be certain that no errors
occurred. If an error code is returned by this
method, and operations were batched, then you should iterate
over all completed operations to find all the operations with
ignored errors.
Example (pseudocode).
We begin by executing a transaction which may have batched
operations and a mix of AO_IgnoreError
and
AbortOnError
abort options:
int execResult= NdbTransaction.execute(args
);
For the number and permitted values of
args
, see
Section 2.3.19.2.5, “NdbTransaction::execute()
”.
Next, because errors on AO_IgnoreError
operations do not affect execResult — that is, the value
returned by execute()
— we check for
errors on the transaction:
NdbError err= NdbTransaction.getNdbError(); if (err.code != 0) {
An nonzero value for the error code means that an error was raised on the transaction. This could be due to any of the following conditions:
A transaction-wide error, such as a data node failure, that caused the transaction to be aborted
A single operation-specific error, such as a constraint violation, that caused the transaction to be aborted
A single operation-specific ignored error, such as no data found, that did not cause the transaction to be aborted
The first of many operation-specific ignored errors, such as no data found when batching, that did not cause the transaction to be aborted
First of a number of operation-specific ignored errors such as no data found (when batching) before an aborting operation error (transaction aborted)
if (execResult != 0) {
The transaction has been aborted. The recommended strategy for handling the error in this case is to test the transaction error status and take appropriate action based on its value:
switch (err.status) { case value1: // statement block handlingvalue1
... case value2: // statement block handlingvalue2
... // (etc. ...) case valueN: // statement block handlingvalueN
... }
Since the transaction was aborted, it is generally necessary to iterate over the completed operations (if any) and find the errors raised by each only if you wish to do so for reporting purposes.
} else {
The transaction itself was not aborted, but there must be one or more ignored errors. In this case, you should iterate over the operations to determine what happened and handle the cause accordingly.
} }
To handle a NdbScanOperation::nextResult()
which returns -1
, indicating that the
operation failed (omitting cases where the operation was
successful):
int nextrc= NdbScanOperation.nextResult(args
);
For the number and permitted values of
args
, see
Section 2.3.18.2.2, “NdbScanOperation::nextResult()
”.
if (nextrc == -1) {
First, you should check the
NdbScanOperation
object for any errors:
NdbError err= NdbScanOperation.getNdbError(); if (err.code == 0) {
No error was found in the scan operation; the error must belong to the transaction as whole.
} err= NdbTransaction.getNdbError();
Now you can handle the error based on the error status:
switch (err.status) { case value1: // statement block handlingvalue1
... case value2: // statement block handlingvalue2
... // (etc. ...) case valueN: // statement block handlingvalueN
... } }
For information about NDB API error classification and status
codes, see Section 5.2.3, “NDB Error Classifications”. While
you should not rely on a specific error code or message text in
your NDB API applications — since error codes and messages
are both subject to change over time — it can be useful to
check error codes and messages to help determine why a
particular failure occurred. For more information about these,
see Section 5.2.2, “NDB Error Codes and Messages”. For more about
NdbError
and the types of information which
can be obtained from NdbError
objects, see
Section 2.3.31, “The NdbError
Structure”.