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.
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:
-
NdbScanOperation::nextResult()
NoteThis method does not perform an implicit
execute()
call. TheNdbBlob
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
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 handling value1 ...
case value2:
// statement block handling value2 ...
// (etc. ...)
case valueN:
// statement block handling valueN ...
}
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
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 handling value1 ...
case value2:
// statement block handling value2 ...
// (etc. ...)
case valueN:
// statement block handling valueN ...
}
}
For information about NDB API error classification and status
codes, see Section 2.4.4, “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 2.4.2, “NDB Error Codes: by Type”. For more about
NdbError
and the types of
information which can be obtained from
NdbError
objects, see
Section 2.3.15, “The NdbError Structure”.