polardbxengine/storage/ndb/include/ndbapi/NdbTransaction.hpp

1472 lines
54 KiB
C++

/*
Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2.0,
as published by the Free Software Foundation.
This program is also distributed with certain software (including
but not limited to OpenSSL) that is licensed under separate terms,
as designated in a particular file or component or in included license
documentation. The authors of MySQL hereby grant you an additional
permission to link the program and your derivative works with the
separately licensed software that they have included with MySQL.
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, version 2.0, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef NdbTransaction_H
#define NdbTransaction_H
#include <ndb_types.h>
#include "NdbError.hpp"
#include "NdbDictionary.hpp"
#include "Ndb.hpp"
#include "NdbOperation.hpp"
#include "NdbIndexScanOperation.hpp"
class NdbTransaction;
class NdbScanOperation;
class NdbIndexScanOperation;
class NdbIndexOperation;
class NdbApiSignal;
class Ndb;
class NdbBlob;
class NdbInterpretedCode;
class NdbQueryImpl;
class NdbQueryDef;
class NdbQuery;
class NdbQueryParamValue;
class NdbLockHandle;
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
// to be documented later
/**
* NdbAsynchCallback functions are used when executing asynchronous
* transactions (using NdbTransaction::executeAsynchPrepare, or
* NdbTransaction::executeAsynch).
* The functions are called when the execute has finished.
* See @ref secAsync for more information.
*/
typedef void (* NdbAsynchCallback)(int, NdbTransaction*, void*);
#endif
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
enum AbortOption {
DefaultAbortOption = NdbOperation::DefaultAbortOption,
CommitIfFailFree = NdbOperation::AbortOnError,
TryCommit = NdbOperation::AbortOnError,
AbortOnError= NdbOperation::AbortOnError,
CommitAsMuchAsPossible = NdbOperation::AO_IgnoreError,
AO_IgnoreError= NdbOperation::AO_IgnoreError
};
enum ExecType {
NoExecTypeDef = -1,
Prepare,
NoCommit,
Commit,
Rollback
};
#endif
/**
* @class NdbTransaction
* @brief Represents a transaction.
*
* A transaction (represented by an NdbTransaction object)
* belongs to an Ndb object and is created using
* Ndb::startTransaction().
* A transaction consists of a list of operations
* (represented by NdbOperation, NdbScanOperation, NdbIndexOperation,
* and NdbIndexScanOperation objects).
* Each operation access exactly one table.
*
* After getting the NdbTransaction object,
* the first step is to get (allocate) an operation given the table name using
* one of the methods getNdbOperation(), getNdbScanOperation(),
* getNdbIndexOperation(), or getNdbIndexScanOperation().
* Then the operation is defined.
* Several operations can be defined on the same
* NdbTransaction object, they will in that case be executed in parallell.
* When all operations are defined, the execute()
* method sends them to the NDB kernel for execution.
*
* The execute() method returns when the NDB kernel has
* completed execution of all operations defined before the call to
* execute(). All allocated operations should be properly defined
* before calling execute().
*
* A call to execute() uses one out of three types of execution:
* -# NdbTransaction::NoCommit Executes operations without committing them.
* -# NdbTransaction::Commit Executes remaining operation and commits the
* complete transaction
* -# NdbTransaction::Rollback Rollbacks the entire transaction.
*
* execute() is equipped with an extra error handling parameter.
* There are two alternatives:
* -# NdbTransaction::AbortOnError (default).
* The transaction is aborted if there are any error during the
* execution
* -# NdbTransaction::AO_IgnoreError
* Continue execution of transaction even if operation fails
*
*/
/* FUTURE IMPLEMENTATION:
* Later a prepare mode will be added when Ndb supports Prepare-To-Commit
* The NdbTransaction can deliver the Transaction Id of the transaction.
* After committing a transaction it is also possible to retrieve the
* global transaction checkpoint which the transaction was put in.
*
* FUTURE IMPLEMENTATION:
* There are three methods for acquiring the NdbOperation.
* -# The first method is the normal where a table name is
* provided. In this case the primary key must be supplied through
* the use of the NdbOperation::equal methods on the NdbOperation object.
* -# The second method provides the tuple identity of the tuple to be
* read. The tuple identity contains a table identifier and will
* thus be possible to use to ensure the attribute names provided
* are correct. If an object-oriented layer is put on top of NDB
* Cluster it is essential that all tables derived from a base
* class has the same attributes with the same type and the same
* name. Thus the application can use the tuple identity and need
* not known the table of the tuple. As long as the table is
* derived from the known base class everything is ok.
* It is not possible to provide any primary key since it is
* already supplied with the call to NdbTransaction::getNdbOperation.
* -# The third method is used when a scanned tuple is to be transferred to
* another transaction. In this case it is not possible to define the
* primary key since it came along from the scanned tuple.
*
*/
class NdbRecord;
class NdbTransaction
{
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
friend class Ndb;
friend class NdbImpl;
friend class NdbOperation;
friend class NdbScanOperation;
friend class NdbIndexOperation;
friend class NdbIndexScanOperation;
friend class NdbBlob;
friend class ha_ndbcluster;
friend class NdbQueryImpl;
friend class NdbQueryOperationImpl;
#endif
public:
#ifdef NDBAPI_50_COMPAT
enum AbortOption {
DefaultAbortOption = NdbOperation::DefaultAbortOption,
CommitIfFailFree = NdbOperation::AbortOnError,
TryCommit = NdbOperation::AbortOnError,
AbortOnError= NdbOperation::AbortOnError,
CommitAsMuchAsPossible = NdbOperation::AO_IgnoreError,
AO_IgnoreError= NdbOperation::AO_IgnoreError
};
#endif
/**
* Execution type of transaction
*/
enum ExecType {
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
NoExecTypeDef=
::NoExecTypeDef, ///< Erroneous type (Used for debugging only)
Prepare= ::Prepare, ///< <i>Missing explanation</i>
#endif
NoCommit= ///< Execute the transaction as far as it has
///< been defined, but do not yet commit it
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
::NoCommit
#endif
,Commit= ///< Execute and try to commit the transaction
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
::Commit
#endif
,Rollback ///< Rollback transaction
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
= ::Rollback
#endif
};
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/**
* Convenience method to fetch this transaction's Ndb* object
*/
Ndb * getNdb() {
return theNdb;
}
#endif
#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
/**
* Get an NdbOperation for a table.
* Note that the operation has to be defined before it is executed.
*
* @note All operations within the same transaction need to
* be initialized with this method.
*
* @param aTableName The table name.
* @return Pointer to an NdbOperation object if successful, otherwise NULL.
*/
NdbOperation* getNdbOperation(const char* aTableName);
#endif
/**
* Get an NdbOperation for a table.
* Note that the operation has to be defined before it is executed.
*
* @note All operations within the same transaction need to
* be initialized with this method.
*
* @param aTable
* A table object (fetched by NdbDictionary::Dictionary::getTable)
* @return Pointer to an NdbOperation object if successful, otherwise NULL.
*/
NdbOperation* getNdbOperation(const NdbDictionary::Table * aTable);
#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
/**
* Get an operation from NdbScanOperation idlelist and
* get the NdbTransaction object which
* was fetched by startTransaction pointing to this operation.
*
* @param aTableName The table name.
* @return pointer to an NdbOperation object if successful, otherwise NULL
*/
NdbScanOperation* getNdbScanOperation(const char* aTableName);
#endif
/**
* Get an operation from NdbScanOperation idlelist and
* get the NdbTransaction object which
* was fetched by startTransaction pointing to this operation.
*
* @param aTable
* A table object (fetched by NdbDictionary::Dictionary::getTable)
* @return pointer to an NdbOperation object if successful, otherwise NULL
*/
NdbScanOperation* getNdbScanOperation(const NdbDictionary::Table * aTable);
#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
/**
* Get an operation from NdbIndexScanOperation idlelist and
* get the NdbTransaction object which
* was fetched by startTransaction pointing to this operation.
*
* @param anIndexName The name of the index to use for scanning
* @param aTableName The name of the table to scan
* @return pointer to an NdbOperation object if successful, otherwise NULL
*/
NdbIndexScanOperation* getNdbIndexScanOperation(const char* anIndexName,
const char* aTableName);
NdbIndexScanOperation* getNdbIndexScanOperation
(const NdbDictionary::Index *anIndex, const NdbDictionary::Table *aTable);
#endif
/**
* Get an operation from NdbIndexScanOperation idlelist and
* get the NdbTransaction object which
* was fetched by startTransaction pointing to this operation.
*
* @param anIndex
An index object (fetched by NdbDictionary::Dictionary::getIndex).
* @return pointer to an NdbOperation object if successful, otherwise NULL
*/
NdbIndexScanOperation* getNdbIndexScanOperation
(const NdbDictionary::Index *anIndex);
#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
/**
* Get an operation from NdbIndexOperation idlelist and
* get the NdbTransaction object that
* was fetched by startTransaction pointing to this operation.
*
* @param anIndexName The index name (as created by createIndex).
* @param aTableName The table name.
* @return Pointer to an NdbIndexOperation object if
* successful, otherwise NULL
*/
NdbIndexOperation* getNdbIndexOperation(const char* anIndexName,
const char* aTableName);
NdbIndexOperation* getNdbIndexOperation(const NdbDictionary::Index *anIndex,
const NdbDictionary::Table *aTable);
#endif
/**
* Get an operation from NdbIndexOperation idlelist and
* get the NdbTransaction object that
* was fetched by startTransaction pointing to this operation.
*
* @param anIndex
* An index object (fetched by NdbDictionary::Dictionary::getIndex).
* @return Pointer to an NdbIndexOperation object if
* successful, otherwise NULL
*/
NdbIndexOperation* getNdbIndexOperation(const NdbDictionary::Index *anIndex);
/**
* Enable/disable schema object ownership check: check that objects used by this
* transaction belong to the dictionary owned by this connection. This is a
* debugging feature for when multiple cluster connections are in use, and has a
* performance cost.
*/
void setSchemaObjOwnerChecks(bool runChecks) { m_enable_schema_obj_owner_check = runChecks; }
/**
* @name Execute Transaction
* @{
*/
/**
* Executes transaction.
*
* @param execType Execution type:<br>
* ExecType::NoCommit executes operations without
* committing them.<br>
* ExecType::Commit executes remaining operations and
* commits the complete transaction.<br>
* ExecType::Rollback rollbacks the entire transaction.
* @param abortOption Handling of error while excuting
* AbortOnError - Abort transaction if an operation fail
* AO_IgnoreError - Accept failing operations
* DefaultAbortOption - Use per-operation abort option
* @param force When operations should be sent to NDB Kernel.
* (See @ref secAdapt.)
* - 0: non-force, adaptive algorithm notices it
* (default);
* - 1: force send, adaptive algorithm notices it;
* - 2: non-force, adaptive algorithm do not notice
* the send.
* @return 0 if successful otherwise -1.
*/
#ifndef NDBAPI_50_COMPAT
int execute(ExecType execType,
NdbOperation::AbortOption = NdbOperation::DefaultAbortOption,
int force = 0 );
#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
int execute(::ExecType execType,
::AbortOption abortOption = ::DefaultAbortOption,
int force = 0 ) {
return execute ((ExecType)execType,
(NdbOperation::AbortOption)abortOption,
force); }
#endif
#else
/**
* 50 compability layer
* Check 50-docs for sematics
*/
int execute(ExecType execType, NdbOperation::AbortOption, int force);
int execute(NdbTransaction::ExecType execType,
NdbTransaction::AbortOption abortOption = AbortOnError,
int force = 0)
{
int ret = execute ((ExecType)execType,
(NdbOperation::AbortOption)abortOption,
force);
if (ret || (abortOption != AO_IgnoreError && theError.code))
return -1;
return 0;
}
#endif
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
// to be documented later
/**
* Prepare an asynchronous transaction.
*
* See @ref secAsync for more information on
* how to use this method.
*
* @param execType Execution type:<br>
* ExecType::NoCommit executes operations without committing them.<br>
* ExecType::Commit executes remaining operations and commits the
* complete transaction.<br>
* ExecType::Rollback rollbacks the entire transaction.
* @param callback A callback method. This method gets
* called when the transaction has been
* executed. See @ref ndbapi_async1.cpp
* for an example on how to specify and use
* a callback method.
* @param anyObject A void pointer. This pointer is forwarded to the
* callback method and can be used to give
* the callback method some data to work on.
* It is up to the application programmer
* to decide on the use of this pointer.
* @param abortOption see @ref execute
*/
#ifndef NDBAPI_50_COMPAT
void executeAsynchPrepare(ExecType execType,
NdbAsynchCallback callback,
void* anyObject,
NdbOperation::AbortOption = NdbOperation::DefaultAbortOption);
#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
void executeAsynchPrepare(::ExecType execType,
NdbAsynchCallback callback,
void* anyObject,
::AbortOption ao = ::DefaultAbortOption) {
executeAsynchPrepare((ExecType)execType, callback, anyObject,
(NdbOperation::AbortOption)ao); }
#endif
#else
/**
* 50 compability layer
* Check 50-docs for sematics
*/
void executeAsynchPrepare(ExecType execType,
NdbAsynchCallback callback,
void* anyObject,
NdbOperation::AbortOption);
void executeAsynchPrepare(NdbTransaction::ExecType execType,
NdbAsynchCallback callback,
void *anyObject,
NdbTransaction::AbortOption abortOption = NdbTransaction::AbortOnError)
{
executeAsynchPrepare((ExecType)execType, callback, anyObject,
(NdbOperation::AbortOption)abortOption);
}
#endif
/**
* Prepare and send an asynchronous transaction.
*
* This method perform the same action as
* NdbTransaction::executeAsynchPrepare
* but also sends the operations to the NDB kernel.
*
* See NdbTransaction::executeAsynchPrepare for information
* about the parameters of this method.
*
* See @ref secAsync for more information on
* how to use this method.
*/
#ifndef NDBAPI_50_COMPAT
void executeAsynch(ExecType aTypeOfExec,
NdbAsynchCallback aCallback,
void* anyObject,
NdbOperation::AbortOption = NdbOperation::DefaultAbortOption,
int forceSend= 0);
#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
void executeAsynch(::ExecType aTypeOfExec,
NdbAsynchCallback aCallback,
void* anyObject,
::AbortOption abortOption= ::DefaultAbortOption,
int forceSend= 0)
{ executeAsynch((ExecType)aTypeOfExec, aCallback, anyObject,
(NdbOperation::AbortOption)abortOption, forceSend); }
#endif
#else
/**
* 50 compability layer
* Check 50-docs for sematics
*/
void executeAsynch(ExecType aTypeOfExec,
NdbAsynchCallback aCallback,
void* anyObject,
NdbOperation::AbortOption = NdbOperation::DefaultAbortOption,
int forceSend= 0);
void executeAsynch(NdbTransaction::ExecType aTypeOfExec,
NdbAsynchCallback aCallback,
void* anyObject,
NdbTransaction::AbortOption abortOption = AbortOnError)
{
executeAsynch((ExecType)aTypeOfExec, aCallback, anyObject,
(NdbOperation::AbortOption)abortOption, 0);
}
#endif
#endif
/**
* Refresh
* Update timeout counter of this transaction
* in the database. If you want to keep the transaction
* active in the database longer than the
* transaction abort timeout.
* @note It's not advised to take a lock on a record and keep it
* for a extended time since this can impact other transactions.
*
*/
int refresh();
/**
* Close transaction
*
* @note Equivalent to to calling Ndb::closeTransaction()
*/
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/**
* @note It is not allowed to call NdbTransaction::close after sending the
* transaction asynchronously before the callback method has
* been called.
* (The application should keep track of the number of
* outstanding transactions and wait until all of them
* has completed before calling NdbTransaction::close).
* If the transaction is not committed it will be aborted.
*/
#endif
void close();
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/**
* Restart transaction
*
* Once a transaction has been completed successfully
* it can be started again wo/ calling closeTransaction/startTransaction
*
* @note This method also releases completed operations
*
* @note This method does not close open scans,
* c.f. NdbScanOperation::close()
*
* @note This method can only be called _directly_ after commit
* and only if commit is successful
*/
int restart();
#endif
/** @} *********************************************************************/
/**
* @name Meta Information
* @{
*/
/**
* Get global checkpoint identity (GCI) of transaction.
*
* Each committed transaction belong to a GCI.
* The log for the committed transaction is saved on
* disk when a global checkpoint occurs.
*
* Whether or not the global checkpoint with this GCI has been
* saved on disk or not cannot be determined by this method.
*
* By comparing the GCI of a transaction with the value
* last GCI restored in a restarted NDB Cluster one can determine
* whether the transaction was restored or not.
*
* @note Global Checkpoint Identity is undefined for scan transactions
* (This is because no updates are performed in scan transactions.)
*
* @return 0 if GCI is available, and stored in <em>gciptr</em>
-1 if GCI is not available.
* (Note that there has to be an NdbTransaction::execute call
* with Ndb::Commit for the GCI to be available.)
*/
int getGCI(Uint64 * gciptr);
/**
* Deprecated...in favor of getGCI(Uint64*)
*/
int getGCI();
/**
* Get transaction identity.
*
* @return Transaction id.
*/
Uint64 getTransactionId();
/**
* The commit status of the transaction.
*/
enum CommitStatusType {
NotStarted, ///< Transaction not yet started
Started, ///< <i>Missing explanation</i>
Committed, ///< Transaction has been committed
Aborted, ///< Transaction has been aborted
NeedAbort ///< <i>Missing explanation</i>
};
/**
* Get the commit status of the transaction.
*
* @return The commit status of the transaction
*/
CommitStatusType commitStatus();
/** @} *********************************************************************/
/**
* @name Error Handling
* @{
*/
/**
* Get error object with information about the latest error.
*
* @return An error object with information about the latest error.
*/
const NdbError & getNdbError() const;
/**
* Get the latest NdbOperation which had an error.
* This method is used on the NdbTransaction object to find the
* NdbOperation causing an error.
* To find more information about the
* actual error, use method NdbOperation::getNdbError()
* on the returned NdbOperation object.
*
* @return The NdbOperation causing the latest error.
* @deprecated Use the const NdbOperation returning variant.
*/
NdbOperation* getNdbErrorOperation();
/**
* Get the latest NdbOperation which had an error.
* This method is used on the NdbTransaction object to find the
* NdbOperation causing an error.
* To find more information about the
* actual error, use method NdbOperation::getNdbError()
* on the returned NdbOperation object.
*
* @return The NdbOperation causing the latest error.
*/
const NdbOperation* getNdbErrorOperation() const;
/**
* Get the method number where the latest error occurred.
*
* @return Line number where latest error occurred.
*/
int getNdbErrorLine();
/**
* Get completed (i.e. executed) operations of a transaction
*
* This method should only be used <em>after</em> a transaction
* has been executed.
* - NdbTransaction::getNextCompletedOperation(NULL) returns the
* first NdbOperation object.
* - NdbTransaction::getNextCompletedOperation(op) returns the
* NdbOperation object defined after the NdbOperation "op".
*
* This method is typically used to fetch all NdbOperation:s of
* a transaction to check for errors (use NdbOperation::getNdbError
* to fetch the NdbError object of an NdbOperation).
*
* @note This method should only be used after the transaction has been
* executed and before the transaction has been closed.
*
* @param op Operation, NULL means get first operation
* @return Operation "after" op
*/
const NdbOperation * getNextCompletedOperation(const NdbOperation * op)const;
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
const NdbOperation* getFirstDefinedOperation()const{return theFirstOpInList;}
const NdbOperation* getLastDefinedOperation()const{return theLastOpInList;}
/** @} *********************************************************************/
/**
* Execute the transaction in NoCommit mode if there are any not-yet
* executed blob part operations of given types. Otherwise do
* nothing. The flags argument is bitwise OR of (1 << optype) where
* optype comes from NdbOperation::OperationType. Only the basic PK
* ops are used (read, insert, update, delete).
*/
int executePendingBlobOps(Uint8 flags = 0xFF);
/**
* Get nodeId of TC for this transaction
*/
Uint32 getConnectedNodeId(); // Get Connected node id
#endif
/*
* NdbRecord primary key and unique key operations.
*
* If the key_rec passed in is for a table, the operation will be a primary
* key operation. If it is for an index, it will be a unique key operation
* using that index.
*
* The key_row passed in defines the primary or unique key of the affected
* tuple, and must remain valid until execute() is called. The key_rec must
* include all columns of the key.
*
* The mask, if != NULL, defines a subset of attributes to read, update, or
* insert. Only if (mask[attrId >> 3] & (1<<(attrId & 7))) is set is the
* column affected. The mask is copied by the methods, so need not remain
* valid after the call returns.
*
* For unique index operations, the attr_rec must refer to the underlying
* table of the index.
*
* OperationOptions can be used to give finer-grained control of operation
* definition. An OperationOptions structure is passed with flags
* indicating which operation definition options are present. Not all
* operation types support all operation options. See the definition of
* the OperationOptions structure for more information on individual options.
*
* Operation type Supported OperationOptions flags
* -------------- --------------------------------
* readTuple OO_ABORTOPTION, OO_GETVALUE,
* OO_PARTITION_ID, OO_INTERPRETED
* insertTuple OO_ABORTOPTION, OO_SETVALUE,
* OO_PARTITION_ID, OO_ANYVALUE
* updateTuple OO_ABORTOPTION, OO_SETVALUE,
* OO_PARTITION_ID, OO_INTERPRETED,
* OO_ANYVALUE
* writeTuple OO_ABORTOPTION, OO_SETVALUE,
* OO_PARTITION_ID, OO_ANYVALUE
* deleteTuple OO_ABORTOPTION, OO_GETVALUE,
* OO_PARTITION_ID, OO_INTERPRETED,
* OO_ANYVALUE
*
* The sizeOfOptions optional parameter is used to allow this interface
* to be backwards compatible with previous definitions of the OperationOptions
* structure. If an unusual size is detected by the interface implementation,
* it can use this to determine how to interpret the passed OperationOptions
* structure. To enable this functionality, the caller should pass
* sizeof(NdbOperation::OperationOptions) for this argument.
*/
const NdbOperation *readTuple(const NdbRecord *key_rec, const char *key_row,
const NdbRecord *result_rec, char *result_row,
NdbOperation::LockMode lock_mode= NdbOperation::LM_Read,
const unsigned char *result_mask= 0,
const NdbOperation::OperationOptions *opts = 0,
Uint32 sizeOfOptions = 0);
const NdbOperation *insertTuple(const NdbRecord *key_rec, const char *key_row,
const NdbRecord *attr_rec, const char *attr_row,
const unsigned char *mask= 0,
const NdbOperation::OperationOptions *opts = 0,
Uint32 sizeOfOptions = 0);
const NdbOperation *insertTuple(const NdbRecord *combined_rec, const char *combined_row,
const unsigned char *mask = 0,
const NdbOperation::OperationOptions *opts = 0,
Uint32 sizeOfOptions = 0);
const NdbOperation *updateTuple(const NdbRecord *key_rec, const char *key_row,
const NdbRecord *attr_rec, const char *attr_row,
const unsigned char *mask= 0,
const NdbOperation::OperationOptions *opts = 0,
Uint32 sizeOfOptions = 0);
const NdbOperation *writeTuple(const NdbRecord *key_rec, const char *key_row,
const NdbRecord *attr_rec, const char *attr_row,
const unsigned char *mask= 0,
const NdbOperation::OperationOptions *opts = 0,
Uint32 sizeOfOptions = 0);
const NdbOperation *deleteTuple(const NdbRecord *key_rec, const char *key_row,
const NdbRecord *result_rec, char *result_row = 0,
const unsigned char *result_mask = 0,
const NdbOperation::OperationOptions *opts = 0,
Uint32 sizeOfOptions = 0);
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
const NdbOperation *refreshTuple(const NdbRecord *key_rec, const char *key_row,
const NdbOperation::OperationOptions *opts = 0,
Uint32 sizeOfOptions = 0);
#endif
/**
* Scan a table, using NdbRecord to read out column data.
*
* The NdbRecord pointed to by result_record must remain valid until
* the scan operation is closed.
*
* The result_mask pointer is optional, if present only columns for
* which the corresponding bit (by attribute id order) in result_mask
* is set will be retrieved in the scan. The result_mask is copied
* internally, so in contrast to result_record need not be valid at
* execute().
*
* A ScanOptions structure can be passed, specifying extra options. See
* the definition of the NdbScanOperation::ScanOptions structure for
* more information.
*
* To enable backwards compatability of this interface, a sizeOfOptions
* parameter can be passed. This parameter indicates the size of the
* ScanOptions structure at the time the client was compiled, and enables
* detection of the use of an old ScanOptions structure. If this
* functionality is not required, it can be left set to zero.
*/
NdbScanOperation *
scanTable(const NdbRecord *result_record,
NdbOperation::LockMode lock_mode= NdbOperation::LM_Read,
const unsigned char *result_mask= 0,
const NdbScanOperation::ScanOptions *options = 0,
Uint32 sizeOfOptions = 0);
/**
* Do an index range scan (optionally ordered) of a table.
*
* The key_record describes the index to be scanned. It must be a key record
* for the index, ie. it must specify (at least) all the key columns of the
* index. And it must be created from the index to be scanned (not from the
* underlying table).
*
* The result_record describes the rows to be returned from the scan. For an
* ordered index scan, result_record must be a key record for the index to
* be scanned, that is it must include at least all of the columns in the
* index (the reason is that the full index key is needed by NDBAPI for merge
* sorting the ordered rows returned from each fragment). The result_record
* must be created from the underlying table, not from the index to be scanned.
*
* Both the key_record and result_record NdbRecord structures must stay
* in-place until the scan operation is closed.
*
* A single IndexBound can either be specified in this call or in a separate
* call to NdbIndexScanOperation::setBound(). To perform a multi range read,
* the scan_flags in the ScanOptions structure must include SF_MULTIRANGE.
* Additional bounds can then be added using multiple calls to
* NdbIndexScanOperation::setBound().
*
* To specify an equals bound, use the same row pointer for the low_key and
* high_key with the low and high inclusive bits set.
*
* A ScanOptions structure can be passed, specifying extra options. See
* the definition of the ScanOptions structure for more information.
*
* To enable backwards compatability of this interface, a sizeOfOptions
* parameter can be passed. This parameter indicates the size of the
* ScanOptions structure at the time the client was compiled, and enables
* detection of the use of an old ScanOptions structure. If this functionality
* is not required, it can be left set to zero.
*
*/
NdbIndexScanOperation *
scanIndex(const NdbRecord *key_record,
const NdbRecord *result_record,
NdbOperation::LockMode lock_mode = NdbOperation::LM_Read,
const unsigned char *result_mask = 0,
const NdbIndexScanOperation::IndexBound *bound = 0,
const NdbScanOperation::ScanOptions *options = 0,
Uint32 sizeOfOptions = 0);
/**
* Add a prepared NdbQueryDef to transaction for execution.
*
* If the NdbQueryDef contains parameters,
* (built with NdbQueryBilder::paramValue()) the value of these
* parameters are specified in the 'paramValue' array. Parameter values
* Should be supplied in the same order as the related paramValue's
* was defined.
*/
NdbQuery*
createQuery(const NdbQueryDef* query,
const NdbQueryParamValue paramValue[]= 0,
NdbOperation::LockMode lock_mode= NdbOperation::LM_Read);
/* LockHandle methods */
/*
* Shared or Exclusive locks taken by read operations in a transaction
* are normally held until the transaction commits or aborts.
* Shared or Exclusive *read* locks can be released before transaction
* commit or abort time by requesting a LockHandle when defining the
* read operation. Any time after the read operation has been executed,
* the LockHandle can be used to create a new Unlock operation. When
* the Unlock operation is executed, the row lock placed by the read
* operation will be released.
*
* The steps are :
* 1) Define the primary key read operation in the normal way
* with lockmode LM_Read or LM_Exclusive
*
* 2) Call NdbOperation::getLockHandle() during operation definition
* (Or set the OO_LOCKHANDLE operation option when calling
* NdbTransaction::readTuple() for NdbRecord)
*
* 3) Call NdbTransaction::execute()
* (Row will be locked from here as normal)
*
* 4) Use the read data, make zero or more calls to
* NdbTransaction::execute() etc.
*
* 5) Call NdbTransaction::unlock(NdbLockHandle*), passing in the
* const LockHandle* from 2) to create an Unlock operation.
*
* 6) Call NdbTransaction::execute()
* (Row will be unlocked from here)
*
* Notes
* - As with other operation types, Unlock operations can be batched.
* - Each LockHandle object refers to a lock placed on a row by a single
* primary key read operation. A single row in the database may have
* concurrent multiple lock holders (of mode LM_Read) and may have
* multiple lock holders pending (LM_Exclusive), so releasing the
* claim of one lock holder may not result in a change to the
* observable lock status of the row.
* - LockHandles are supported for Scan lock takeover operations - the
* lockhandle must be requested before the locktakeover is executed.
* - LockHandles and Unlock operations are not supported for Unique Index
* read operations.
*/
/* unlock
*
* This method creates an Unlock operation on the current transaction.
* When executed, the Unlock operation will remove the lock referenced
* by the passed LockHandle.
*
* The unlock operation can fail, for example due to the row being
* unlocked already. In this scenario, the AbortOption specifies how
* this will be handled.
* The default is that errors will cause transaction abort.
*/
const NdbOperation* unlock(const NdbLockHandle* lockHandle,
NdbOperation::AbortOption ao = NdbOperation::DefaultAbortOption);
/* releaseLockHandle
* This method is used to release a LockHandle object once it
* is no longer required.
* For NdbRecord primary key read operations, this cannot be
* called until the associated read operation has executed.
* All LockHandles associated with a transaction are released
* when it is closed.
*/
int releaseLockHandle(const NdbLockHandle* lockHandle);
/* Get maximum number of pending Blob read/write bytes before
* an automatic execute() occurs
*/
Uint32 getMaxPendingBlobReadBytes() const;
Uint32 getMaxPendingBlobWriteBytes() const;
/* Set maximum number of pending Blob read/write bytes before
* an automatic execute() occurs
*/
void setMaxPendingBlobReadBytes(Uint32 bytes);
void setMaxPendingBlobWriteBytes(Uint32 bytes);
private:
/**
* Release completed operations
*/
void releaseCompletedOperations();
void releaseCompletedQueries();
typedef Uint64 TimeMillis_t;
/**************************************************************************
* These methods are service methods to other classes in the NDBAPI. *
**************************************************************************/
/**************************************************************************
* These are the create and delete methods of this class. *
**************************************************************************/
NdbTransaction(Ndb* aNdb);
~NdbTransaction();
int init(); // Initialize connection object for new transaction
int executeNoBlobs(ExecType execType,
NdbOperation::AbortOption = NdbOperation::DefaultAbortOption,
int force = 0 );
/**
* Set Connected node id
* and sequence no
*/
void setConnectedNodeId( Uint32 nodeId, Uint32 sequence);
void setMyBlockReference( int ); // Set my block refrerence
void setTC_ConnectPtr( Uint32 ); // Sets TC Connect pointer
int getTC_ConnectPtr(); // Gets TC Connect pointer
void setBuddyConPtr(Uint32); // Sets Buddy Con Ptr
Uint32 getBuddyConPtr(); // Gets Buddy Con Ptr
NdbTransaction* next(); // Returns the next pointer
void next(NdbTransaction*); // Sets the next pointer
enum ConStatusType {
NotConnected,
Connecting,
Connected,
DisConnecting,
ConnectFailure
};
ConStatusType Status(); // Read the status information
void Status(ConStatusType); // Set the status information
Uint32 get_send_size(); // Get size to send
void set_send_size(Uint32); // Set size to send;
int receiveTCSEIZECONF(const NdbApiSignal* anApiSignal);
int receiveTCSEIZEREF(const NdbApiSignal* anApiSignal);
int receiveTCRELEASECONF(const NdbApiSignal* anApiSignal);
int receiveTCRELEASEREF(const NdbApiSignal* anApiSignal);
int receiveTC_COMMITCONF(const class TcCommitConf *, Uint32 len);
int receiveTCKEYCONF(const class TcKeyConf *, Uint32 aDataLength);
int receiveTCKEY_FAILCONF(const class TcKeyFailConf *);
int receiveTCKEY_FAILREF(const NdbApiSignal* anApiSignal);
int receiveTC_COMMITREF(const NdbApiSignal* anApiSignal);
int receiveTCROLLBACKCONF(const NdbApiSignal* anApiSignal);
int receiveTCROLLBACKREF(const NdbApiSignal* anApiSignal);
int receiveTCROLLBACKREP(const NdbApiSignal* anApiSignal);
int receiveTCINDXREF(const NdbApiSignal*);
int receiveSCAN_TABREF(const NdbApiSignal*);
int receiveSCAN_TABCONF(const NdbApiSignal*, const Uint32*, Uint32 len);
int doSend(); // Send all operations
int sendROLLBACK(); // Send of an ROLLBACK
int sendTC_HBREP(); // Send a TCHBREP signal;
int sendCOMMIT(); // Send a TC_COMMITREQ signal;
void setGCI(int GCI); // Set the global checkpoint identity
int OpCompleteFailure();
int OpCompleteSuccess();
void OpSent(); // Operation Sent with success
// Free connection related resources and close transaction
void release();
// Release all operations in connection
void releaseOperations();
// Release all cursor operations in connection
void releaseOps(NdbOperation*);
void releaseQueries(NdbQueryImpl*);
void releaseScanOperations(NdbIndexScanOperation*);
bool releaseScanOperation(NdbIndexScanOperation** listhead,
NdbIndexScanOperation** listtail,
NdbIndexScanOperation* op);
void releaseLockHandles();
// Set the transaction identity of the transaction
void setTransactionId(Uint64 aTransactionId);
// Indicate something went wrong in the definition phase
void setErrorCode(int anErrorCode);
// Indicate something went wrong in the definition phase
void setOperationErrorCode(int anErrorCode);
// Indicate something went wrong in the definition phase
void setOperationErrorCodeAbort(int anErrorCode, int abortOption = -1);
int checkMagicNumber(); // Verify correct object
Uint32 getMagicNumberFromObject() const;
static Uint32 getMagicNumber() { return (Uint32)0x37412619; }
NdbOperation* getNdbOperation(const class NdbTableImpl* aTable,
NdbOperation* aNextOp = 0);
NdbIndexScanOperation* getNdbScanOperation(const class NdbTableImpl* aTable);
NdbIndexOperation* getNdbIndexOperation(const class NdbIndexImpl* anIndex,
const class NdbTableImpl* aTable,
NdbOperation* aNextOp = 0);
NdbIndexScanOperation* getNdbIndexScanOperation(const NdbIndexImpl* index,
const NdbTableImpl* table);
NdbOperation *setupRecordOp(NdbOperation::OperationType type,
NdbOperation::LockMode lock_mode,
NdbOperation::AbortOption default_ao,
const NdbRecord *key_record,
const char *key_row,
const NdbRecord *attribute_record,
const char *attribute_row,
const unsigned char *mask,
const NdbOperation::OperationOptions *opts,
Uint32 sizeOfOptions,
const NdbLockHandle* lh = 0);
void handleExecuteCompletion();
/****************************************************************************
* These are the private variables of this class.
****************************************************************************/
Uint32 ptr2int();
Uint32 theId;
// Keeps track of what the send method should do.
enum SendStatusType {
NotInit,
InitState,
sendOperations,
sendCompleted,
sendCOMMITstate,
sendABORT,
sendABORTfail,
sendTC_ROLLBACK,
sendTC_COMMIT,
sendTC_OP
};
SendStatusType theSendStatus;
NdbAsynchCallback theCallbackFunction; // Pointer to the callback function
void* theCallbackObject; // The callback object pointer
Uint32 theTransArrayIndex; // Current index in a transaction
// array for this object
TimeMillis_t theStartTransTime; // Start time of the transaction
NdbError theError; // Errorcode on transaction
int theErrorLine; // Method number of last error in NdbOperation
NdbOperation* theErrorOperation; // The NdbOperation where the error occurred
Ndb* theNdb; // Pointer to Ndb object
NdbTransaction* theNext; // Next pointer. Used in idle list.
NdbOperation* theFirstOpInList; // First operation in defining list.
NdbOperation* theLastOpInList; // Last operation in defining list.
NdbOperation* theFirstExecOpInList; // First executing operation in list
NdbOperation* theLastExecOpInList; // Last executing operation in list.
NdbOperation* theCompletedFirstOp; // First & last operation in completed
NdbOperation* theCompletedLastOp; // operation list.
Uint32 theNoOfOpSent; // How many operations have been sent
Uint32 theNoOfOpCompleted; // How many operations have completed
Uint32 theMyRef; // Our block reference
Uint32 theTCConPtr; // Transaction Co-ordinator connection pointer.
Uint64 theTransactionId; // theTransactionId of the transaction
Uint64 theGlobalCheckpointId; // The gloabl checkpoint identity of the transaction
Uint64 *p_latest_trans_gci; // Reference to latest gci for connection
ConStatusType theStatus; // The status of the connection
enum CompletionStatus {
NotCompleted,
CompletedSuccess,
CompletedFailure,
DefinitionFailure
} theCompletionStatus; // The Completion status of the transaction
CommitStatusType theCommitStatus; // The commit status of the transaction
Uint32 theMagicNumber; // Magic Number to verify correct object
// Current meanings :
// 0x00FE11DC : NdbTransaction not in use
// 0x37412619 : NdbTransaction in use
// 0x00FE11DF : NdbTransaction for scan operation
// scan definition not yet complete
Uint32 thePriority; // Transaction Priority
enum ReturnType { ReturnSuccess, ReturnFailure };
ReturnType theReturnStatus; // Did we have any read/update/delete failing
// to find the tuple.
bool theTransactionIsStarted;
bool theInUseState;
bool theSimpleState;
enum ListState {
NotInList,
InPreparedList,
InSendList,
InCompletedList
} theListState;
Uint32 theDBnode; // The database node we are connected to
Uint32 theNodeSequence; // The sequence no of the db node
bool theReleaseOnClose;
/**
* handle transaction spanning
* multiple TC/db nodes
*
* 1) Bitmask with used nodes
* 2) Bitmask with nodes failed during op
*/
Uint32 m_db_nodes[5];
Uint32 m_failed_db_nodes[5];
int report_node_failure(Uint32 id);
// Scan operations
bool m_waitForReply;
NdbIndexScanOperation* m_theFirstScanOperation;
NdbIndexScanOperation* m_theLastScanOperation;
NdbIndexScanOperation* m_firstExecutedScanOp;
// Scan operations or queries:
// The operation or query actually performing the scan.
// (Only one of theScanningOp/m_scanningQuery be non-NULL,
// which indirectly indicates the type)
NdbScanOperation* theScanningOp;
Uint32 theBuddyConPtr;
// optim: any blobs
bool theBlobFlag;
Uint8 thePendingBlobOps;
Uint32 maxPendingBlobReadBytes;
Uint32 maxPendingBlobWriteBytes;
Uint32 pendingBlobReadBytes;
Uint32 pendingBlobWriteBytes;
inline bool hasBlobOperation() { return theBlobFlag; }
static void sendTC_COMMIT_ACK(class NdbImpl *, NdbApiSignal *,
Uint32 transId1, Uint32 transId2,
Uint32 aBlockRef,
bool send_immediate);
void completedFail(const char * s);
#ifdef VM_TRACE
void printState();
#endif
bool checkState_TransId(const Uint32 * transId) const;
// Check table and index objects wrt current connection - for debugging
bool checkSchemaObjects(const NdbTableImpl *tab, const NdbIndexImpl *idx=0);
void remove_list(NdbOperation*& head, NdbOperation*);
void define_scan_op(NdbIndexScanOperation*);
NdbLockHandle* m_theFirstLockHandle;
NdbLockHandle* m_theLastLockHandle;
NdbLockHandle* getLockHandle();
friend class HugoOperations;
friend struct Ndb_free_list_t<NdbTransaction>;
NdbTransaction(const NdbTransaction&); // Not impl.
NdbTransaction&operator=(const NdbTransaction&);
// Query operation (aka multicursor)
NdbQueryImpl* m_firstQuery; // First query in defining list.
NdbQueryImpl* m_firstExecQuery; // First query to send for execution
NdbQueryImpl* m_firstActiveQuery; // First query actively executing, or completed
// Scan operations or queries:
// The operation or query actually performing the scan.
// (Only one of theScanningOp/m_scanningQuery be non-NULL,
// which indirectly indicates the type)
NdbQueryImpl* m_scanningQuery;
Uint32 m_tcRef;
bool m_enable_schema_obj_owner_check;
};
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
inline
Uint32
NdbTransaction::get_send_size()
{
return 0;
}
inline
void
NdbTransaction::set_send_size(Uint32 send_size)
{
(void)send_size; //unused
return;
}
#ifdef NDB_NO_DROPPED_SIGNAL
#include <stdlib.h>
#endif
inline
Uint32
NdbTransaction::getMagicNumberFromObject() const
{
return theMagicNumber;
}
inline
int
NdbTransaction::checkMagicNumber()
{
if (theMagicNumber == getMagicNumber())
return 0;
else {
#ifdef NDB_NO_DROPPED_SIGNAL
abort();
#endif
return -1;
}
}
inline
bool
NdbTransaction::checkState_TransId(const Uint32 * transId) const
{
const NdbTransaction::ConStatusType tStatus = theStatus;
const Uint64 tTransactionId = theTransactionId;
const Uint32 tTmp1 = transId[0];
const Uint32 tTmp2 = transId[1];
Uint64 tRecTransId = (Uint64)tTmp1 + ((Uint64)tTmp2 << 32);
bool b = (tStatus == Connected) && (tTransactionId == tRecTransId);
return b;
}
/************************************************************************************************
void setTransactionId(Uint64 aTransactionId);
Remark: Set the transaction identity.
************************************************************************************************/
inline
void
NdbTransaction::setTransactionId(Uint64 aTransactionId)
{
theTransactionId = aTransactionId;
}
inline
void
NdbTransaction::setConnectedNodeId(Uint32 aNode, Uint32 aSequenceNo)
{
theDBnode = aNode;
theNodeSequence = aSequenceNo;
}
/******************************************************************************
int getConnectedNodeId();
Return Value: Return theDBnode.
Remark: Get Connected node id.
******************************************************************************/
inline
Uint32
NdbTransaction::getConnectedNodeId()
{
return theDBnode;
}
/******************************************************************************
void setMyBlockReference(int aBlockRef);
Parameters: aBlockRef: The block refrerence.
Remark: Set my block refrerence.
******************************************************************************/
inline
void
NdbTransaction::setMyBlockReference(int aBlockRef)
{
theMyRef = aBlockRef;
}
/******************************************************************************
void setTC_ConnectPtr(Uint32 aTCConPtr);
Parameters: aTCConPtr: The connection pointer.
Remark: Sets TC Connect pointer.
******************************************************************************/
inline
void
NdbTransaction::setTC_ConnectPtr(Uint32 aTCConPtr)
{
theTCConPtr = aTCConPtr;
}
/******************************************************************************
int getTC_ConnectPtr();
Return Value: Return theTCConPtr.
Remark: Gets TC Connect pointer.
******************************************************************************/
inline
int
NdbTransaction::getTC_ConnectPtr()
{
return theTCConPtr;
}
inline
void
NdbTransaction::setBuddyConPtr(Uint32 aBuddyConPtr)
{
theBuddyConPtr = aBuddyConPtr;
}
inline
Uint32 NdbTransaction::getBuddyConPtr()
{
return theBuddyConPtr;
}
/******************************************************************************
NdbTransaction* next();
Return Value: Return next pointer to NdbTransaction object.
Remark: Get the next pointer.
******************************************************************************/
inline
NdbTransaction*
NdbTransaction::next()
{
return theNext;
}
/******************************************************************************
void next(NdbTransaction aTransaction);
Parameters: aTransaction: The connection object.
Remark: Sets the next pointer.
******************************************************************************/
inline
void
NdbTransaction::next(NdbTransaction* aTransaction)
{
theNext = aTransaction;
}
/******************************************************************************
ConStatusType Status();
Return Value Return the ConStatusType.
Parameters: aStatus: The status.
Remark: Sets Connect status.
******************************************************************************/
inline
NdbTransaction::ConStatusType
NdbTransaction::Status()
{
return theStatus;
}
/******************************************************************************
void Status(ConStatusType aStatus);
Parameters: aStatus: The status.
Remark: Sets Connect status.
******************************************************************************/
inline
void
NdbTransaction::Status( ConStatusType aStatus )
{
theStatus = aStatus;
}
/******************************************************************************
void OpSent();
Remark: An operation was sent with success that expects a response.
******************************************************************************/
inline
void
NdbTransaction::OpSent()
{
theNoOfOpSent++;
}
/******************************************************************************
void executePendingBlobOps();
******************************************************************************/
inline
int
NdbTransaction::executePendingBlobOps(Uint8 flags)
{
if (thePendingBlobOps & flags) {
// not executeNoBlobs because there can be new ops with blobs
return execute(NoCommit);
}
return 0;
}
inline
Uint32
NdbTransaction::ptr2int(){
return theId;
}
typedef NdbTransaction NdbConnection;
#endif // ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
#endif