diff options
Diffstat (limited to 'storage/ndb/include/ndbapi')
20 files changed, 8935 insertions, 0 deletions
diff --git a/storage/ndb/include/ndbapi/Ndb.hpp b/storage/ndb/include/ndbapi/Ndb.hpp new file mode 100644 index 00000000000..726a58c591d --- /dev/null +++ b/storage/ndb/include/ndbapi/Ndb.hpp @@ -0,0 +1,1762 @@ +/* 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 */ + +/** + @mainpage NDB API Programmers' Guide + + This guide assumes a basic familiarity with MySQL Cluster concepts found + on http://dev.mysql.com/doc/mysql/en/NDBCluster.html . + Some of the fundamental ones are also described in section @ref secConcepts. + + The NDB API is a MySQL Cluster application interface + that implements transactions. + The NDB API consists of the following fundamental classes: + - Ndb_cluster_connection, representing a connection to a cluster, + - Ndb is the main class, representing a connection to a database, + - NdbTransaction represents a transaction, + - NdbOperation represents an operation using a primary key, + - NdbScanOperation represents an operation performing a full table scan. + - NdbIndexOperation represents an operation using a unique hash index, + - NdbIndexScanOperation represents an operation performing a scan using + an ordered index, + - NdbRecAttr represents an attribute value + - NdbDictionary represents meta information about tables and attributes. + + In addition, the NDB API defines a structure NdbError, which contains the + specification for an error. + + It is also possible to receive "events" triggered when data in the database in changed. + This is done through the NdbEventOperation class. + + There are also some auxiliary classes, which are listed in the class hierarchy. + + The main structure of an application program is as follows: + -# Connect to a cluster using the Ndb_cluster_connection + object. + -# Initiate a database connection by constructing and initialising one or more Ndb objects. + -# Define and execute transactions using the NdbTransaction class. + -# Delete Ndb objects. + -# Terminate the connection to the cluster (terminate instance of Ndb_cluster_connection). + + The procedure for using transactions is as follows: + -# Start transaction (instantiate an NdbTransaction object) + -# Add and define operations associated with the transaction using instances of one or more of the + NdbOperation, NdbScanOperation, NdbIndexOperation, and NdbIndexScanOperation classes + -# Execute transaction (call NdbTransaction::execute()) + + The operation can be of two different types, + <var>Commit</var> or <var>NoCommit</var>. + If the operation is of type <var>NoCommit</var>, + then the application program executes the operation part of a transaction, + but without actually committing the transaction. + After executing a <var>NoCommit</var> operation, the program can continue + to add and define more operations to the transaction + for later execution. + + If the operation is of type <var>Commit</var>, then the transaction is + immediately committed. The transaction <em>must</em> be closed after it has been + commited (event if commit fails), and no further addition or definition of + operations for this transaction is allowed. + + @section secSync Synchronous Transactions + + Synchronous transactions are defined and executed as follows: + + -# Start (create) the transaction, which is + referenced by an NdbTransaction object + (typically created using Ndb::startTransaction()). + At this point, the transaction is only being defined, + and is not yet sent to the NDB kernel. + -# Define operations and add them to the transaction, using one or more of + - NdbTransaction::getNdbOperation() + - NdbTransaction::getNdbScanOperation() + - NdbTransaction::getNdbIndexOperation() + - NdbTransaction::getNdbIndexScanOperation() + along with the appropriate methods of the respective NdbOperation class + (or one possiblt one or more of its subclasses). + Note that the transaction has still not yet been sent to the NDB kernel. + -# Execute the transaction, using the NdbTransaction::execute() method. + -# Close the transaction (call Ndb::closeTransaction()). + + For an example of this process, see the program listing in + @ref ndbapi_simple.cpp. + + To execute several parallel synchronous transactions, one can either + use multiple Ndb objects in several threads, or start multiple + application programs. + + @section secNdbOperations Operations + + A NdbTransaction consists of a list of operations, each of which is represented + by an instance of NdbOperation, NdbScanOperation, NdbIndexOperation, or + NdbIndexScanOperation. + + <h3>Single row operations</h3> + After the operation is created using NdbTransaction::getNdbOperation() + (or NdbTransaction::getNdbIndexOperation()), it is defined in the following + three steps: + -# Define the standard operation type, using NdbOperation::readTuple() + -# Specify search conditions, using NdbOperation::equal() + -# Specify attribute actions, using NdbOperation::getValue() + + Here are two brief examples illustrating this process. For the sake of + brevity, we omit error handling. + + This first example uses an NdbOperation: + @code + // 1. Retrieve table object + myTable= myDict->getTable("MYTABLENAME"); + + // 2. Create + myOperation= myTransaction->getNdbOperation(myTable); + + // 3. Define type of operation and lock mode + myOperation->readTuple(NdbOperation::LM_Read); + + // 4. Specify Search Conditions + myOperation->equal("ATTR1", i); + + // 5. Attribute Actions + myRecAttr= myOperation->getValue("ATTR2", NULL); + @endcode + For additional examples of this sort, see @ref ndbapi_simple.cpp. + + The second example uses an NdbIndexOperation: + @code + // 1. Retrieve index object + myIndex= myDict->getIndex("MYINDEX", "MYTABLENAME"); + + // 2. Create + myOperation= myTransaction->getNdbIndexOperation(myIndex); + + // 3. Define type of operation and lock mode + myOperation->readTuple(NdbOperation::LM_Read); + + // 4. Specify Search Conditions + myOperation->equal("ATTR1", i); + + // 5. Attribute Actions + myRecAttr = myOperation->getValue("ATTR2", NULL); + @endcode + Another example of this second type can be found in + @ref ndbapi_simple_index.cpp. + + We will now discuss in somewhat greater detail each step involved in the + creation and use of synchronous transactions. + + <h4>Step 1: Define single row operation type</h4> + The following operation types are supported: + -# NdbOperation::insertTuple() : + inserts a non-existing tuple + -# NdbOperation::writeTuple() : + updates an existing tuple if is exists, + otherwise inserts a new tuple + -# NdbOperation::updateTuple() : + updates an existing tuple + -# NdbOperation::deleteTuple() : + deletes an existing tuple + -# NdbOperation::readTuple() : + reads an existing tuple with specified lock mode + + All of these operations operate on the unique tuple key. + (When NdbIndexOperation is used then all of these operations + operate on a defined unique hash index.) + + @note If you want to define multiple operations within the same transaction, + then you need to call NdbTransaction::getNdbOperation() or + NdbTransaction::getNdbIndexOperation() for each operation. + + <h4>Step 2: Specify Search Conditions</h4> + The search condition is used to select tuples. Search conditions are set using NdbOperation::equal(). + + <h4>Step 3: Specify Attribute Actions</h4> + Next, it is necessary to determine which attributes should be read or updated. + It is important to remember that: + - Deletes can neither read nor set values, but only delete them + - Reads can only read values + - Updates can only set values + Normally the attribute is identified by name, but it is + also possible to use the attribute's identity to determine the + attribute. + + NdbOperation::getValue() returns an NdbRecAttr object + containing the read value. + To obtain the actual value, one of two methods can be used; + the application can either + - use its own memory (passed through a pointer aValue) to + NdbOperation::getValue(), or + - receive the attribute value in an NdbRecAttr object allocated + by the NDB API. + + The NdbRecAttr object is released when Ndb::closeTransaction() + is called. + Thus, the application cannot reference this object following + any subsequent call to Ndb::closeTransaction(). + Attempting to read data from an NdbRecAttr object before + calling NdbTransaction::execute() yields an undefined result. + + + @subsection secScan Scan Operations + + Scans are roughly the equivalent of SQL cursors, providing a means to + preform high-speed row processing. A scan can be performed + on either a table (using @ref NdbScanOperation) or + an ordered index (by means of an @ref NdbIndexScanOperation). + + Scan operations are characterised by the following: + - They can perform only reads (shared, exclusive or dirty) + - They can potentially work with multiple rows + - They can be used to update or delete multiple rows + - They can operate on several nodes in parallel + + After the operation is created using NdbTransaction::getNdbScanOperation() + (or NdbTransaction::getNdbIndexScanOperation()), + it is carried out in the following three steps: + -# Define the standard operation type, using NdbScanOperation::readTuples() + -# Specify search conditions, using @ref NdbScanFilter and/or + @ref NdbIndexScanOperation::setBound() + -# Specify attribute actions, using NdbOperation::getValue() + -# Executing the transaction, using NdbTransaction::execute() + -# Traversing the result set by means of succssive calls to + NdbScanOperation::nextResult() + + Here are two brief examples illustrating this process. Once again, in order + to keep things relatively short and simple, we will forego any error handling. + + This first example performs a table scan, using an NdbScanOperation: + @code + // 1. Retrieve table object + myTable= myDict->getTable("MYTABLENAME"); + + // 2. Create + myOperation= myTransaction->getNdbScanOperation(myTable); + + // 3. Define type of operation and lock mode + myOperation->readTuples(NdbOperation::LM_Read); + + // 4. Specify Search Conditions + NdbScanFilter sf(myOperation); + sf.begin(NdbScanFilter::OR); + sf.eq(0, i); // Return rows with column 0 equal to i or + sf.eq(1, i+1); // column 1 equal to (i+1) + sf.end(); + + // 5. Attribute Actions + myRecAttr= myOperation->getValue("ATTR2", NULL); + @endcode + + Our second example uses an NdbIndexScanOperation to perform an index scan: + @code + // 1. Retrieve index object + myIndex= myDict->getIndex("MYORDEREDINDEX", "MYTABLENAME"); + + // 2. Create + myOperation= myTransaction->getNdbIndexScanOperation(myIndex); + + // 3. Define type of operation and lock mode + myOperation->readTuples(NdbOperation::LM_Read); + + // 4. Specify Search Conditions + // All rows with ATTR1 between i and (i+1) + myOperation->setBound("ATTR1", NdbIndexScanOperation::BoundGE, i); + myOperation->setBound("ATTR1", NdbIndexScanOperation::BoundLE, i+1); + + // 5. Attribute Actions + myRecAttr = MyOperation->getValue("ATTR2", NULL); + @endcode + + Some additional discussion of each step required to perform a scan follows: + + <h4>Step 1: Define Scan Operation Type</h4> + It is important to remember that only a single operation is supported for each scan operation + (@ref NdbScanOperation::readTuples() or @ref NdbIndexScanOperation::readTuples()). + + @note If you want to define multiple scan operations within the same + transaction, then you need to call + NdbTransaction::getNdbScanOperation() or + NdbTransaction::getNdbIndexScanOperation() separately for <b>each</b> operation. + + <h4>Step 2: Specify Search Conditions</h4> + The search condition is used to select tuples. + If no search condition is specified, the scan will return all rows + in the table. + + The search condition can be an @ref NdbScanFilter (which can be used on both + @ref NdbScanOperation and @ref NdbIndexScanOperation) or bounds which + can only be used on index scans (@ref NdbIndexScanOperation::setBound()). + An index scan can use both NdbScanFilter and bounds. + + @note When NdbScanFilter is used, each row is examined, whether or not it is + actually returned. However, when using bounds, only rows within the bounds will be examined. + + <h4>Step 3: Specify Attribute Actions</h4> + + Next, it is necessary to define which attributes should be read. + As with transaction attributes, scan attributes are defined by name but it is + also possible to use the attributes' identities to define attributes. + + As previously discussed (see @ref secSync), the value read is returned as + an NdbRecAttr object by the NdbOperation::getValue() method. + + <h3>Using Scan to Update/Delete</h3> + Scanning can also be used to update or delete rows. + This is performed by + -# Scanning using exclusive locks (using NdbOperation::LM_Exclusive) + -# When iterating through the result set, for each row optionally calling + either NdbScanOperation::updateCurrentTuple() or + NdbScanOperation::deleteCurrentTuple() + -# (If performing NdbScanOperation::updateCurrentTuple():) + Setting new values for records simply by using @ref NdbOperation::setValue(). + NdbOperation::equal() should <em>not</em> be called in such cases, as the primary + key is retrieved from the scan. + + @note The actual update or delete will not be performed until the next + call to NdbTransaction::execute(), just as with single row operations. + NdbTransaction::execute() also must be called before any locks are released; + see @ref secScanLocks for more information. + + <h4>Features Specific to Index Scans</h4> + + When performing an index scan, it is possible to + scan only a subset of a table using @ref NdbIndexScanOperation::setBound(). + In addition, result sets can be sorted in either ascending or descending order, using + @ref NdbIndexScanOperation::readTuples(). Note that rows are returned unordered + by default, that is, unless <var>sorted</var> is set to <b>true</b>. + It is also important to note that, when using NdbIndexScanOperation::BoundEQ + on a partition key, only fragments containing rows will actually be scanned. + + @note When performing a sorted scan, any value passed as the + NdbIndexScanOperation::readTuples() method's <code>parallel</code> argument + will be ignored and maximum parallelism will be used instead. In other words, all + fragments which it is possible to scan will be scanned simultaneously and in parallel + in such cases. + + @subsection secScanLocks Lock handling with scans + + Performing scans on either a tables or an index has the potential + return a great many records; however, Ndb will lock only a predetermined + number of rows per fragment at a time. + How many rows will be locked per fragment is controlled by the + <var>batch</var> parameter passed to NdbScanOperation::readTuples(). + + In order to allow the application to handle how locks are released, + NdbScanOperation::nextResult() has a Boolean parameter <var>fetch_allow</var>. + If NdbScanOperation::nextResult() is called with <var>fetch_allow</var> equal to + <b>false</b>, then no locks may be released as result of the function call. + Otherwise the locks for the current batch may be released. + + This next example shows a scan delete that handle locks in an efficient manner. + For the sake of brevity, we omit error-handling. + @code + int check; + + // Outer loop for each batch of rows + while((check = MyScanOperation->nextResult(true)) == 0) + { + do + { + // Inner loop for each row within batch + MyScanOperation->deleteCurrentTuple(); + } while((check = MyScanOperation->nextResult(false)) == 0); + + // When no more rows in batch, exeute all defined deletes + MyTransaction->execute(NoCommit); + } + @endcode + + See @ref ndbapi_scan.cpp for a more complete example of a scan. + + @section secError Error Handling + + Errors can occur either when operations making up a transaction are being + defined, or when the transaction is actually being executed. Catching and + handling either sort of error requires testing the value returned by + NdbTransaction::execute(), and then, if an error is indicated (that is, + if this value is equal to -1), using the following two methods in order to + identify the error's type and location: + + - NdbTransaction::getNdbErrorOperation() returns a reference to the + operation causing the most recent error. + - NdbTransaction::getNdbErrorLine() yields the method number of the + erroneous method in the operation. + + This short example illustrates how to detect an error and to use these + two methods to identify it: + + @code + theTransaction = theNdb->startTransaction(); + theOperation = theTransaction->getNdbOperation("TEST_TABLE"); + if (theOperation == NULL) goto error; + theOperation->readTuple(NdbOperation::LM_Read); + theOperation->setValue("ATTR_1", at1); + theOperation->setValue("ATTR_2", at1); // Error occurs here + theOperation->setValue("ATTR_3", at1); + theOperation->setValue("ATTR_4", at1); + + if (theTransaction->execute(Commit) == -1) { + errorLine = theTransaction->getNdbErrorLine(); + errorOperation = theTransaction->getNdbErrorOperation(); + } + @endcode + + Here <code>errorLine</code> will be 3, as the error occurred in the + third method called on the NdbOperation object (in this case, + <code>theOperation</code>); if the result of + NdbTransaction::getNdbErrorLine() is 0, this means that the error + occurred when the operations were executed. In this example, + <code>errorOperation</code> will be a pointer to the <code>theOperation</code> + object. The NdbTransaction::getNdbError() method returns an NdbError + object providing information about the error. + + @note Transactions are <b>not</b> automatically closed when an error occurs. Call + Ndb::closeTransaction() to close the transaction. + + One recommended way to handle a transaction failure + (i.e. an error is reported) is to: + -# Rollback transaction (call NdbTransaction::execute() with a special parameter) + -# Close transaction (call NdbTransaction::closeTransaction()) + -# If the error was temporary, attempt to restart the transaction + + Several errors can occur when a transaction contains multiple + operations which are simultaneously executed. + In this case the application has to go through all operations + and query their NdbError objects to find out what really happened. + + It is also important to note that errors can occur even when a commit is + reported as successful. In order to handle such situations, the NDB API + provides an additional NdbTransaction::commitStatus() method to check the + transactions's commit status. + +******************************************************************************/ + +/** + * @page ndbapi_simple.cpp ndbapi_simple.cpp + * @include ndbapi_simple.cpp + */ + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL +/** + * @page ndbapi_async.cpp ndbapi_async.cpp + * @include ndbapi_async.cpp + */ +/** + * @page ndbapi_async1.cpp ndbapi_async1.cpp + * @include ndbapi_async1.cpp + */ +#endif + +/** + * @page ndbapi_retries.cpp ndbapi_retries.cpp + * @include ndbapi_retries.cpp + */ + +/** + * @page ndbapi_simple_index.cpp ndbapi_simple_index.cpp + * @include ndbapi_simple_index.cpp + */ + +/** + * @page ndbapi_scan.cpp ndbapi_scan.cpp + * @include ndbapi_scan.cpp + */ + +/** + * @page ndbapi_event.cpp ndbapi_event.cpp + * @include ndbapi_event.cpp + */ + + +/** + @page secAdapt Adaptive Send Algorithm + + At the time of "sending" a transaction + (using NdbTransaction::execute()), the transactions + are in reality <em>not</em> immediately transfered to the NDB Kernel. + Instead, the "sent" transactions are only kept in a + special send list (buffer) in the Ndb object to which they belong. + The adaptive send algorithm decides when transactions should + actually be transferred to the NDB kernel. + + The NDB API is designed as a multi-threaded interface and so + it is often desirable to transfer database operations from more than + one thread at a time. + The NDB API keeps track of which Ndb objects are active in transferring + information to the NDB kernel and the expected amount of threads to + interact with the NDB kernel. + Note that a given instance of Ndb should be used in at most one thread; + different threads should <em>not</em> use the same Ndb object. + + There are four conditions leading to the transfer of database + operations from Ndb object buffers to the NDB kernel: + -# The NDB Transporter (TCP/IP, SCI or shared memory) + decides that a buffer is full and sends it off. + The buffer size is implementation-dependent and + may change between MySQL Cluster releases. + On TCP/IP the buffer size is usually around 64 KB; + Since each Ndb object provides a single buffer per storage node, + the notion of a "full" buffer is local to this storage node. + -# The accumulation of statistical data on transferred information + may force sending of buffers to all storage nodes. + -# Every 10 ms, a special transmission thread checks whether or not + any send activity has occurred. If not, then the thread will + force transmission to all nodes. + This means that 20 ms is the maximum time database operations + are kept waiting before being sent off. The 10-millisecond limit + is likely to become a configuration parameter in + future releases of MySQL Cluster; however, for checks that + are more frequent than each 10 ms, + additional support from the operating system is required. + -# For methods that are affected by the adaptive send alorithm + (such as NdbTransaction::execute()), there is a <var>force</var> + parameter + that overrides its default behaviour in this regard and forces + immediate transmission to all nodes. See the inidvidual NDB API class + listings for more information. + + @note The conditions listed above are subject to change in future releases + of MySQL Cluster. +*/ + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL +/** + + For each of these "sent" transactions, there are three + possible states: + -# Waiting to be transferred to NDB Kernel. + -# Has been transferred to the NDB Kernel and is currently + being processed. + -# Has been transferred to the NDB Kernel and has + finished processing. + Now it is waiting for a call to a poll method. + (When the poll method is invoked, + then the transaction callback method will be executed.) + + The poll method invoked (either Ndb::pollNdb() or Ndb::sendPollNdb()) + will return when: + -# at least 'minNoOfEventsToWakeup' of the transactions + in the send list have transitioned to state 3 as described above, and + -# all of these transactions have executed their callback methods. +*/ +#endif + +/** + @page secConcepts MySQL Cluster Concepts + + The <em>NDB Kernel</em> is the collection of storage nodes + belonging to a MySQL Cluster. + The application programmer can for most purposes view the + set of all storage nodes as a single entity. + Each storage node is made up of three main components: + - TC : The transaction co-ordinator + - ACC : Index storage component + - TUP : Data storage component + + When an application program executes a transaction, + it connects to one transaction co-ordinator on one storage node. + Usually, the programmer does not need to specify which TC should be used, + but in some cases when performance is important, the programmer can + provide "hints" to use a certain TC. + (If the node with the desired transaction co-ordinator is down, then another TC will + automatically take over the work.) + + Every storage node has an ACC and a TUP which store + the indexes and data portions of the database table fragment. + Even though one TC is responsible for the transaction, + several ACCs and TUPs on other storage nodes might be involved in the + execution of the transaction. + + + @section secNdbKernelConnection Selecting a Transaction Co-ordinator + + The default method is to select the transaction co-ordinator (TC) determined to be + the "closest" storage node, using a heuristic for proximity based on + the type of transporter connection. In order of closest to most distant, these are + - SCI + - SHM + - TCP/IP (localhost) + - TCP/IP (remote host) + If there are several connections available with the same proximity, they will each be + selected in a round robin fashion for every transaction. Optionally + one may set the method for TC selection to round-robin mode, where each new set of + transactions is placed on the next DB node. The pool of connections from which this + selection is made consists of all available connections. + + As noted previously, the application programmer can provide hints to the NDB API as to + which transaction co-ordinator it should use. This is done by + providing a <em>table</em> and <em>partition key</em> + (usually the primary key). + By using the primary key as the partition key, + the transaction will be placed on the node where the primary replica + of that record resides. + Note that this is only a hint; the system can be + reconfigured at any time, in which case the NDB API will choose a transaction + co-ordinator without using the hint. + For more information, see NdbDictionary::Column::getPartitionKey() and + Ndb::startTransaction(). The application programmer can specify + the partition key from SQL by using the construct, + <code>CREATE TABLE ... ENGINE=NDB PARTITION BY KEY (<var>attribute-list</var>);</code>. + + + @section secRecordStruct NDB Record Structure + The NDB Cluster engine used by MySQL Cluster is a relational database engine + storing records in tables just as with any other RDBMS. + Table rows represent records as tuples of relational data. + When a new table is created, its attribute schema is specified for the table as a whole, + and thus each record of the table has the same structure. Again, this is typical + of relational databases, and NDB is no different in this regard. + + + @subsection secKeys Primary Keys + Each record has from 1 up to 32 attributes which belong + to the primary key of the table. + + @section secTrans Transactions + + Transactions are committed first to main memory, + and then to disk after a global checkpoint (GCP) is issued. + Since all data is (in most NDB Cluster configurations) + synchronously replicated and stored on multiple NDB nodes, + the system can still handle processor failures without loss + of data. + However, in the case of a system failure (e.g. the whole system goes down), + then all (committed or not) transactions occurring since the latest GCP are lost. + + + @subsection secConcur Concurrency Control + NDB Cluster uses pessimistic concurrency control based on locking. + If a requested lock (implicit and depending on database operation) + cannot be attained within a specified time, + then a timeout error occurs. + + Concurrent transactions as requested by parallel application programs and + thread-based applications can sometimes deadlock when they try to access + the same information simultaneously. + Thus, applications need to be written in a manner so that timeout errors + occurring due to such deadlocks are handled gracefully. This generally + means that the transaction encountering a timeout should be rolled back + and restarted. + + + @section secHint Hints and Performance + + Placing the transaction co-ordinator in close proximity + to the actual data used in the transaction can in many cases + improve performance significantly. This is particularly true for + systems using TCP/IP. For example, a Solaris system using a single 500 MHz processor + has a cost model for TCP/IP communication which can be represented by the formula + + <code>[30 microseconds] + ([100 nanoseconds] * [<var>number of bytes</var>])</code> + + This means that if we can ensure that we use "popular" links we increase + buffering and thus drastically reduce the communication cost. + The same system using SCI has a different cost model: + + <code>[5 microseconds] + ([10 nanoseconds] * [<var>number of bytes</var>])</code> + + Thus, the efficiency of an SCI system is much less dependent on selection of + transaction co-ordinators. + Typically, TCP/IP systems spend 30-60% of their working time on communication, + whereas for SCI systems this figure is closer to 5-10%. + Thus, employing SCI for data transport means that less care from the NDB API + programmer is required and greater scalability can be achieved, even for + applications using data from many different parts of the database. + + A simple example is an application that uses many simple updates where + a transaction needs to update one record. + This record has a 32 bit primary key, + which is also the partition key. + Then the keyData will be the address of the integer + of the primary key and keyLen will be 4. +*/ + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL +/** + (A transaction's execution can also be divided into three + steps: prepare, send, and poll. This allows us to perform asynchronous + transactions. More about this later.) +*/ +#endif +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL +/** + Another way to execute several parallel transactions is to use + asynchronous transactions. +*/ +#endif +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL +/** + Operations are of two different kinds: + -# standard operations, and + -# interpreted program operations. +*/ +#endif +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL +/** + <h3>Interpreted Program Operations</h3> + The following types of interpreted program operations exist: + -# NdbOperation::interpretedUpdateTuple : + updates a tuple using an interpreted program + -# NdbOperation::interpretedDeleteTuple : + delete a tuple using an interpreted program + + The operations interpretedUpdateTuple and interpretedDeleteTuple both + work using the unique tuple key. + + These <em>interpreted programs</em> + make it possible to perform computations + inside the NDB Cluster Kernel instead of in the application + program. + This is sometimes very effective, since no intermediate results + are sent to the application, only the final result. + + + <h3>Interpreted Update and Delete</h3> + + Operations for interpreted updates and deletes must follow a + certain order when defining operations on a tuple. + As for read and write operations, + one must first define the operation type and then the search key. + -# The first step is to define the initial readings. + In this phase it is only allowed to use the + NdbOperation::getValue method. + This part might be empty. + -# The second step is to define the interpreted part. + The methods supported are the methods listed below except + NdbOperation::def_subroutine and NdbOperation::ret_sub + which can only be used in a subroutine. + NdbOperation::incValue and NdbOperation::subValue + increment and decrement attributes + (currently only unsigned integers supported). + This part can also be empty since interpreted updates + can be used for reading and updating the same tuple. + <p> + Even though getValue and setValue are not really interpreted + program instructions, it is still allowed to use them as + the last instruction of the program. + (If a getValue or setValue is found when an interpret_exit_ok + could have been issued then the interpreted_exit_ok + will be inserted. + A interpret_exit_ok should be viewed as a jump to the first + instruction after the interpreted instructions.) + -# The third step is to define all updates without any + interpreted program instructions. + Here a set of NdbOperation::setValue methods are called. + There might be zero such calls. + -# The fourth step is the final readings. + The initial readings reads the initial value of attributes + and the final readings reads them after their updates. + There might be zero NdbOperation::getValue calls. + -# The fifth step is possible subroutine definitions using + NdbOperation::def_subroutine and NdbOperation::ret_sub. +*/ +#endif +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL +/** + <h3>Interpreted Programs</h3> + Interpretation programs are executed in a + register-based virtual machine. + The virtual machine has eight 64 bit registers numbered 0-7. + Each register contains type information which is used both + for type conversion and for type checking. + + @note Arrays are currently <b>not</b> supported in the virtual machine. + Currently only unsigned integers are supported and of size + maximum 64 bits. + + All errors in the interpretation program will cause a + transaction abort, but will not affect any other transactions. + + The following are legal interpreted program instructions: + -# incValue : Add to an attribute + -# subValue : Subtract from an attribute + -# def_label : Define a label in the interpreted program + -# add_reg : Add two registers + -# sub_reg : Subtract one register from another + -# load_const_u32 : Load an unsigned 32 bit value into a register + -# load_const_u64 : Load an unsigned 64 bit value into a register + -# load_const_null : Load a NULL value into a register + -# read_attr : Read attribute value into a register + -# write_attr : Write a register value into an attribute + -# branch_ge : Compares registers and possibly jumps to specified label + -# branch_gt : Compares registers and possibly jumps to specified label + -# branch_le : Compares registers and possibly jumps to specified label + -# branch_lt : Compares registers and possibly jumps to specified label + -# branch_eq : Compares registers and possibly jumps to specified label + -# branch_ne : Compares registers and possibly jumps to specified label + -# branch_ne_null : Jumps if register does not contain NULL value + -# branch_eq_null : Jumps if register contains NULL value + -# branch_label : Unconditional jump to label + -# interpret_exit_ok : Exit interpreted program + (approving tuple if used in scan) + -# interpret_exit_nok : Exit interpreted program + (disqualifying tuple if used in scan) + + There are also three instructions for subroutines, which + are described in the next section. + + @subsection subsubSub Interpreted Programs: Subroutines + + The following are legal interpreted program instructions for + subroutines: + -# NdbOperation::def_subroutine : + Defines start of subroutine in interpreted program code + -# NdbOperation::call_sub : + Calls a subroutine + -# NdbOperation::ret_sub : + Return from subroutine + + The virtual machine executes subroutines using a stack for + its operation. + The stack allows for up to 24 subroutine calls in succession. + Deeper subroutine nesting will cause an abort of the transaction. + + All subroutines starts with the instruction + NdbOperation::def_subroutine and ends with the instruction + NdbOperation::ret_sub. + If it is necessary to return earlier in the subroutine + it has to be done using a branch_label instruction + to a label defined right before the + NdbOperation::ret_sub instruction. + + @note The subroutines are automatically numbered starting with 0. + The parameter used by NdbOperation::def_subroutine + should match the automatic numbering to make it easier to + debug the interpreted program. +*/ +#endif + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL +/** + @section secAsync Asynchronous Transactions + The asynchronous interface is used to increase the speed of + transaction executing by better utilizing the connection + between the application and the NDB Kernel. + The interface is used to send many transactions + at the same time to the NDB kernel. + This is often much more efficient than using synchronous transactions. + The main reason for using this method is to ensure that + Sending many transactions at the same time ensures that bigger + chunks of data are sent when actually sending and thus decreasing + the operating system overhead. + + The synchronous call to NdbTransaction::execute + normally performs three main steps:<br> + -# <b>Prepare</b> + Check transaction status + - if problems, abort the transaction + - if ok, proceed + -# <b>Send</b> + Send the defined operations since last execute + or since start of transaction. + -# <b>Poll</b> + Wait for response from NDB kernel. + + The asynchronous method NdbTransaction::executeAsynchPrepare + only perform step 1. + (The abort part in step 1 is only prepared for. The actual + aborting of the transaction is performed in a later step.) + + Asynchronous transactions are defined and executed + in the following way. + -# Start (create) transactions (same way as for the + synchronous transactions) + -# Add and define operations (also as in the synchronous case) + -# <b>Prepare</b> transactions + (using NdbTransaction::executeAsynchPrepare or + NdbTransaction::executeAsynch) + -# <b>Send</b> transactions to NDB Kernel + (using Ndb::sendPreparedTransactions, + NdbTransaction::executeAsynch, or Ndb::sendPollNdb) + -# <b>Poll</b> NDB kernel to find completed transactions + (using Ndb::pollNdb or Ndb::sendPollNdb) + -# Close transactions (same way as for the synchronous transactions) + + See example program in section @ref ndbapi_example2.cpp. + + This prepare-send-poll protocol actually exists in four variants: + - (Prepare-Send-Poll). This is the one-step variant provided + by synchronous transactions. + - (Prepare-Send)-Poll. This is the two-step variant using + NdbTransaction::executeAsynch and Ndb::pollNdb. + - Prepare-(Send-Poll). This is the two-step variant using + NdbTransaction::executeAsynchPrepare and Ndb::sendPollNdb. + - Prepare-Send-Poll. This is the three-step variant using + NdbTransaction::executeAsynchPrepare, Ndb::sendPreparedTransactions, and + Ndb::pollNdb. + + Transactions first has to be prepared by using method + NdbTransaction::executeAsynchPrepare or NdbTransaction::executeAsynch. + The difference between these is that + NdbTransaction::executeAsynch also sends the transaction to + the NDB kernel. + One of the arguments to these methods is a callback method. + The callback method is executed during polling (item 5 above). + + Note that NdbTransaction::executeAsynchPrepare does not + send the transaction to the NDB kernel. When using + NdbTransaction::executeAsynchPrepare, you either have to call + Ndb::sendPreparedTransactions or Ndb::sendPollNdb to send the + database operations. + (Ndb::sendPollNdb also polls Ndb for completed transactions.) + + The methods Ndb::pollNdb and Ndb::sendPollNdb checks if any + sent transactions are completed. The method Ndb::sendPollNdb + also send all prepared transactions before polling NDB. + Transactions still in the definition phase (i.e. items 1-3 above, + transactions which has not yet been sent to the NDB kernel) are not + affected by poll-calls. + The poll method invoked (either Ndb::pollNdb or Ndb::sendPollNdb) + will return when: + -# at least 'minNoOfEventsToWakeup' of the transactions + are finished processing, and + -# all of these transactions have executed their + callback methods. + + The poll method returns the number of transactions that + have finished processing and executed their callback methods. + + @note When an asynchronous transaction has been started and sent to + the NDB kernel, it is not allowed to execute any methods on + objects belonging to this transaction until the transaction + callback method have been executed. + (The transaction is stated and sent by either + NdbTransaction::executeAsynch or through the combination of + NdbTransaction::executeAsynchPrepare and either + Ndb::sendPreparedTransactions or Ndb::sendPollNdb). + + More about how transactions are sent the NDB Kernel is + available in section @ref secAdapt. +*/ +#endif + + +/** + + Put this back when real array ops are supported + i.e. get/setValue("kalle[3]"); + + @subsection secArrays Array Attributes + A table attribute in NDB Cluster can be of type <var>Array</var>, + meaning that the attribute consists of an ordered sequence of + elements. In such cases, <var>attribute size</var> is the size + (expressed in bits) of any one element making up the array; the + <var>array size</var> is the number of elements in the array. + +*/ + +#ifndef Ndb_H +#define Ndb_H + +#include <ndb_types.h> +#include <ndbapi_limits.h> +#include <ndb_cluster_connection.hpp> +#include <NdbError.hpp> +#include <NdbDictionary.hpp> + +class NdbObjectIdMap; +class NdbOperation; +class NdbEventOperationImpl; +class NdbScanOperation; +class NdbIndexScanOperation; +class NdbIndexOperation; +class NdbTransaction; +class NdbApiSignal; +class NdbRecAttr; +class NdbLabel; +class NdbBranch; +class NdbSubroutine; +class NdbCall; +class Table; +class BaseString; +class NdbEventOperation; +class NdbBlob; +class NdbReceiver; +class TransporterFacade; +class PollGuard; +class Ndb_local_table_info; +template <class T> struct Ndb_free_list_t; + +typedef void (* NdbEventCallback)(NdbEventOperation*, Ndb*, void*); + +#define WAITFOR_RESPONSE_TIMEOUT 120000 // Milliseconds + +#define NDB_SYSTEM_DATABASE "sys" +#define NDB_SYSTEM_SCHEMA "def" + +/** + * @class Ndb + * @brief Represents the NDB kernel and is the main class of the NDB API. + * + * Always start your application program by creating an Ndb object. + * By using several Ndb objects it is possible to design + * a multi-threaded application, but note that Ndb objects + * cannot be shared by several threads. + * Different threads should use different Ndb objects. + * A thread might however use multiple Ndb objects. + * Currently there is a limit of maximum 128 Ndb objects + * per application process. + * + * @note It is not allowed to call methods in the NDB API + * on the same Ndb object in different threads + * simultaneously (without special handling of the + * Ndb object). + * + * @note The Ndb object is multi-thread safe in the following manner. + * Each Ndb object can ONLY be handled in one thread. + * If an Ndb object is handed over to another thread then the + * application must ensure that a memory barrier is used to + * ensure that the new thread see all updates performed by + * the previous thread. + * Semaphores, mutexes and so forth are easy ways of issuing memory + * barriers without having to bother about the memory barrier concept. + * + */ + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL +// to be documented later +/* + * If one Ndb object is used to handle parallel transactions through the + * asynchronous programming interface, please read the notes regarding + * asynchronous transactions (Section @ref secAsync). + * The asynchronous interface provides much higher performance + * in some situations, but is more complicated for the application designer. + * + * @note Each Ndb object should either use the methods for + * asynchronous transaction or the methods for + * synchronous transactions but not both. + */ +#endif + +class Ndb +{ +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + friend class NdbReceiver; + friend class NdbOperation; + friend class NdbEventOperationImpl; + friend class NdbEventBuffer; + friend class NdbTransaction; + friend class Table; + friend class NdbApiSignal; + friend class NdbIndexOperation; + friend class NdbScanOperation; + friend class NdbIndexScanOperation; + friend class NdbDictionaryImpl; + friend class NdbDictInterface; + friend class NdbBlob; + friend class NdbImpl; +#endif + +public: + /** + * @name General + * @{ + */ + /** + * The Ndb object represents a connection to a database. + * + * @note The init() method must be called before the Ndb object may actually be used. + * + * @param ndb_cluster_connection is a connection to the cluster containing + * the database to be used + * @param aCatalogName is the name of the catalog to be used. + * @note The catalog name provides a namespace for the tables and + * indexes created in any connection from the Ndb object. + * @param aSchemaName is the name of the schema you + * want to use. + * @note The schema name provides an additional namespace + * for the tables and indexes created in a given catalog. + */ + Ndb(Ndb_cluster_connection *ndb_cluster_connection, + const char* aCatalogName = "", const char* aSchemaName = "def"); + + ~Ndb(); + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + /** + * The current ndb_cluster_connection get_ndb_cluster_connection. + * + * @return the current connection + */ + Ndb_cluster_connection& get_ndb_cluster_connection(); +#endif + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + /** + * The current catalog name can be fetched by getCatalogName. + * + * @return the current catalog name + */ + const char * getCatalogName() const; + + /** + * The current catalog name can be set by setCatalogName. + * + * @param aCatalogName is the new name of the current catalog + */ + void setCatalogName(const char * aCatalogName); + + /** + * The current schema name can be fetched by getSchemaName. + * + * @return the current schema name + */ + const char * getSchemaName() const; + + /** + * The current schema name can be set by setSchemaName. + * + * @param aSchemaName is the new name of the current schema + */ + void setSchemaName(const char * aSchemaName); +#endif + + /** + * The current database name can be fetched by getDatabaseName. + * + * @return the current database name + */ + const char * getDatabaseName() const; + + /** + * The current database name can be set by setDatabaseName. + * + * @param aDatabaseName is the new name of the current database + */ + void setDatabaseName(const char * aDatabaseName); + + /** + * The current database schema name can be fetched by getDatabaseSchemaName. + * + * @return the current database schema name + */ + const char * getDatabaseSchemaName() const; + + /** + * The current database schema name can be set by setDatabaseSchemaName. + * + * @param aDatabaseSchemaName is the new name of the current database schema + */ + void setDatabaseSchemaName(const char * aDatabaseSchemaName); + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + /** Set database and schema name to match previously retrieved table + * + * Returns non-zero if table internal name does not contain + * non-empty database and schema names + */ + int setDatabaseAndSchemaName(const NdbDictionary::Table* t); +#endif + + /** + * Initializes the Ndb object + * + * @param maxNoOfTransactions + * Maximum number of parallel + * NdbTransaction objects that can be handled by the Ndb object. + * Maximum value is 1024. + * + * @note each scan or index scan operation uses one extra + * NdbTransaction object + * + * @return 0 if successful, -1 otherwise. + */ + int init(int maxNoOfTransactions = 4); + +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + /** + * Wait for Ndb object to successfully set-up connections to + * the NDB kernel. + * Starting to use the Ndb object without using this method + * gives unspecified behavior. + * + * @param timeout The maximum time we will wait for + * the initiation process to finish. + * Timeout is expressed in seconds. + * @return 0: Ndb is ready and timeout has not occurred.<br> + * -1: Timeout has expired + */ + int waitUntilReady(int timeout = 60); +#endif + + /** @} *********************************************************************/ + + /** + * @name Meta Information + * @{ + */ + + /** + * Get an object for retrieving or manipulating database schema information + * + * @note this object operates outside any transaction + * + * @return Object containing meta information about all tables + * in NDB Cluster. + */ + class NdbDictionary::Dictionary* getDictionary() const; + + + /** @} *********************************************************************/ + + /** + * @name Event subscriptions + * @{ + */ + + /** + * Create a subcription to an event defined in the database + * + * @param eventName + * unique identifier of the event + * + * @return Object representing an event, NULL on failure + */ + NdbEventOperation* createEventOperation(const char* eventName); + /** + * Drop a subscription to an event + * + * @param eventOp + * Event operation + * + * @return 0 on success + */ + int dropEventOperation(NdbEventOperation* eventOp); + + /** + * Wait for an event to occur. Will return as soon as an event + * is detected on any of the created events. + * + * @param aMillisecondNumber + * maximum time to wait + * + * @return > 0 if events available, 0 if no events available, < 0 on failure + */ + int pollEvents(int aMillisecondNumber, Uint64 *latestGCI= 0); + + /** + * Returns an event operation that has data after a pollEvents + * + * @return an event operations that has data, NULL if no events left with data. + */ + NdbEventOperation *nextEvent(); + + /** + * Iterate over distinct event operations which are part of current + * GCI. Valid after nextEvent. Used to get summary information for + * the epoch (e.g. list of all tables) before processing event data. + * + * Set *iter=0 to start. Returns NULL when no more. If event_types + * is not NULL, it returns bitmask of received event types. + */ + const NdbEventOperation* + getGCIEventOperations(Uint32* iter, Uint32* event_types); + + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + int flushIncompleteEvents(Uint64 gci); + NdbEventOperation *getEventOperation(NdbEventOperation* eventOp= 0); + Uint64 getLatestGCI(); + void forceGCP(); + void setReportThreshEventGCISlip(unsigned thresh); + void setReportThreshEventFreeMem(unsigned thresh); +#endif + + /** @} *********************************************************************/ + + /** + * @name Starting and Closing Transactions + * @{ + */ + + /** + * Start a transaction + * + * @note When the transaction is completed it must be closed using + * Ndb::closeTransaction or NdbTransaction::close. + * The transaction must be closed independent of its outcome, i.e. + * even if there is an error. + * + * @param table Pointer to table object used for deciding + * which node to run the Transaction Coordinator on + * @param keyData Pointer to partition key corresponding to + * <var>table</var> + * @param keyLen Length of partition key expressed in bytes + * + * @return NdbTransaction object, or NULL on failure. + */ + NdbTransaction* startTransaction(const NdbDictionary::Table *table= 0, + const char *keyData = 0, + Uint32 keyLen = 0); + + /** + * Close a transaction. + * + * @note should be called after the transaction has completed, irrespective + * of success or failure + */ +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + /** + * @note It is not allowed to call Ndb::closeTransaction after sending the + * transaction asynchronously with either + * Ndb::sendPreparedTransactions or + * Ndb::sendPollNdb 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 Ndb::closeTransaction). + * If the transaction is not committed it will be aborted. + */ +#endif + void closeTransaction(NdbTransaction*); + + /** @} *********************************************************************/ + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + // to be documented later + /** + * @name Asynchronous Transactions + * @{ + */ + + /** + * Wait for prepared transactions. + * Will return as soon as at least 'minNoOfEventsToWakeUp' + * of them have completed, or the maximum time given as timeout has passed. + * + * @param aMillisecondNumber + * Maximum time to wait for transactions to complete. Polling + * without wait is achieved by setting the timer to zero. + * Time is expressed in milliseconds. + * @param minNoOfEventsToWakeup Minimum number of transactions + * which has to wake up before the poll-call will return. + * If minNoOfEventsToWakeup is + * set to a value larger than 1 then this is the minimum + * number of transactions that need to complete before the + * poll will return. + * Setting it to zero means that one should wait for all + * outstanding transactions to return before waking up. + * @return Number of transactions polled. + */ + int pollNdb(int aMillisecondNumber = WAITFOR_RESPONSE_TIMEOUT, + int minNoOfEventsToWakeup = 1); + + /** + * This send method will send all prepared database operations. + * The default method is to do it non-force and instead + * use the adaptive algorithm. (See Section @ref secAdapt.) + * The second option is to force the sending and + * finally there is the third alternative which is + * also non-force but also making sure that the + * adaptive algorithm do not notice the send. + * In this case the sending will be performed on a + * cyclical 10 millisecond event. + * + * @param forceSend 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. + */ + void sendPreparedTransactions(int forceSend = 0); + + /** + * This is a send-poll variant that first calls + * Ndb::sendPreparedTransactions and then Ndb::pollNdb. + * It is however somewhat faster than calling the methods + * separately, since some mutex-operations are avoided. + * See documentation of Ndb::pollNdb and Ndb::sendPreparedTransactions + * for more details. + * + * @param aMillisecondNumber Timeout specifier + * Polling without wait is achieved by setting the + * millisecond timer to zero. + * @param minNoOfEventsToWakeup Minimum number of transactions + * which has to wake up before the poll-call will return. + * If minNoOfEventsToWakeup is + * set to a value larger than 1 then this is the minimum + * number of transactions that need to complete before the + * poll-call will return. + * Setting it to zero means that one should wait for all + * outstanding transactions to return before waking up. + * @param forceSend 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 does not notice the send. + * @return Number of transactions polled. + */ + int sendPollNdb(int aMillisecondNumber = WAITFOR_RESPONSE_TIMEOUT, + int minNoOfEventsToWakeup = 1, + int forceSend = 0); + /** @} *********************************************************************/ +#endif + + /** + * @name Error Handling + * @{ + */ + + /** + * Get the NdbError object + * + * @note The NdbError object is valid until a new NDB API method is called. + */ + const NdbError & getNdbError() const; + + /** + * Get a NdbError object for a specific error code + * + * The NdbError object is valid until you call a new NDB API method. + */ + const NdbError & getNdbError(int errorCode); + + + /** @} *********************************************************************/ + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + /** + * Get the application node identity. + * + * @return Node id of this application. + */ + int getNodeId(); + + bool usingFullyQualifiedNames(); + + /** + * Different types of tampering with the NDB Cluster. + * <b>Only for debugging purposes only.</b> + */ + enum TamperType { + LockGlbChp = 1, ///< Lock GCP + UnlockGlbChp, ///< Unlock GCP + CrashNode, ///< Crash an NDB node + ReadRestartGCI, ///< Request the restart GCI id from NDB Cluster + InsertError ///< Execute an error in NDB Cluster + ///< (may crash system) + }; + + /** + * For testing purposes it is possible to tamper with the NDB Cluster + * (i.e. send a special signal to DBDIH, the NDB distribution handler). + * <b>This feature should only used for debugging purposes.</b> + * In a release versions of NDB Cluster, + * this call always return -1 and does nothing. + * + * @param aAction Action to be taken according to TamperType above + * + * @param aNode Which node the action will be taken + * -1: Master DIH. + * 0-16: Nodnumber. + * @return -1 indicates error, other values have meaning dependent + * on type of tampering. + */ + int NdbTamper(TamperType aAction, int aNode); + + /** + * Return a unique tuple id for a table. The id sequence is + * ascending but may contain gaps. Methods which have no + * TupleIdRange argument use NDB API dict cache. They may + * not be called from mysqld. + * + * @param aTableName table name + * + * @param cacheSize number of values to cache in this Ndb object + * + * @return 0 or -1 on error, and tupleId in out parameter + */ + struct TupleIdRange { + TupleIdRange() {} + Uint64 m_first_tuple_id; + Uint64 m_last_tuple_id; + void reset() { + m_first_tuple_id = ~(Uint64)0; + m_last_tuple_id = ~(Uint64)0; + }; + }; + + int initAutoIncrement(); + + int getAutoIncrementValue(const char* aTableName, + Uint64 & tupleId, Uint32 cacheSize); + int getAutoIncrementValue(const NdbDictionary::Table * aTable, + Uint64 & tupleId, Uint32 cacheSize); + int getAutoIncrementValue(const NdbDictionary::Table * aTable, + TupleIdRange & range, Uint64 & tupleId, + Uint32 cacheSize); + int readAutoIncrementValue(const char* aTableName, + Uint64 & tupleId); + int readAutoIncrementValue(const NdbDictionary::Table * aTable, + Uint64 & tupleId); + int readAutoIncrementValue(const NdbDictionary::Table * aTable, + TupleIdRange & range, Uint64 & tupleId); + int setAutoIncrementValue(const char* aTableName, + Uint64 tupleId, bool increase); + int setAutoIncrementValue(const NdbDictionary::Table * aTable, + Uint64 tupleId, bool increase); + int setAutoIncrementValue(const NdbDictionary::Table * aTable, + TupleIdRange & range, Uint64 tupleId, + bool increase); +private: + int getTupleIdFromNdb(const NdbTableImpl* table, + TupleIdRange & range, Uint64 & tupleId, + Uint32 cacheSize); + int readTupleIdFromNdb(const NdbTableImpl* table, + TupleIdRange & range, Uint64 & tupleId); + int setTupleIdInNdb(const NdbTableImpl* table, + TupleIdRange & range, Uint64 tupleId, bool increase); + int opTupleIdOnNdb(const NdbTableImpl* table, + TupleIdRange & range, Uint64 & opValue, Uint32 op); +public: + + /** + */ + NdbTransaction* hupp( NdbTransaction* ); + Uint32 getReference() const { return theMyRef;} + + struct Free_list_usage + { + const char * m_name; + Uint32 m_created; + Uint32 m_free; + Uint32 m_sizeof; + }; + + Free_list_usage * get_free_list_usage(Free_list_usage*); +#endif + + + +/***************************************************************************** + * These are service routines used by the other classes in the NDBAPI. + ****************************************************************************/ + Uint32 get_cond_wait_index() { return cond_wait_index; } + void set_cond_wait_index(Uint32 index) { cond_wait_index = index; } +private: + Uint32 cond_wait_index; + Ndb *cond_signal_ndb; + void cond_signal(); + + void setup(Ndb_cluster_connection *ndb_cluster_connection, + const char* aCatalogName, const char* aSchemaName); + + void connected(Uint32 block_reference); + void report_node_connected(Uint32 nodeId); + + + NdbTransaction* startTransactionLocal(Uint32 aPrio, Uint32 aFragmentId); + +// Connect the connection object to the Database. + int NDB_connect(Uint32 tNode); + NdbTransaction* doConnect(Uint32 nodeId); + void doDisconnect(); + + NdbReceiver* getNdbScanRec();// Get a NdbScanReceiver from idle list + NdbLabel* getNdbLabel(); // Get a NdbLabel from idle list + NdbBranch* getNdbBranch(); // Get a NdbBranch from idle list + NdbSubroutine* getNdbSubroutine();// Get a NdbSubroutine from idle + NdbCall* getNdbCall(); // Get a NdbCall from idle list + NdbApiSignal* getSignal(); // Get an operation from idle list + NdbRecAttr* getRecAttr(); // Get a receeive attribute object from + // idle list of the Ndb object. + NdbOperation* getOperation(); // Get an operation from idle list + NdbIndexScanOperation* getScanOperation(); // Get a scan operation from idle + NdbIndexOperation* getIndexOperation();// Get an index operation from idle + + NdbBlob* getNdbBlob();// Get a blob handle etc + + void releaseSignal(NdbApiSignal* anApiSignal); + void releaseSignalsInList(NdbApiSignal** pList); + void releaseNdbScanRec(NdbReceiver* aNdbScanRec); + void releaseNdbLabel(NdbLabel* anNdbLabel); + void releaseNdbBranch(NdbBranch* anNdbBranch); + void releaseNdbSubroutine(NdbSubroutine* anNdbSubroutine); + void releaseNdbCall(NdbCall* anNdbCall); + void releaseRecAttr (NdbRecAttr* aRecAttr); + void releaseOperation(NdbOperation* anOperation); + void releaseScanOperation(NdbIndexScanOperation*); + void releaseNdbBlob(NdbBlob* aBlob); + + void check_send_timeout(); + void remove_sent_list(Uint32); + Uint32 insert_completed_list(NdbTransaction*); + Uint32 insert_sent_list(NdbTransaction*); + + // Handle a received signal. Used by both + // synchronous and asynchronous interface + void handleReceivedSignal(NdbApiSignal* anApiSignal, struct LinearSectionPtr ptr[3]); + + int sendRecSignal(Uint16 aNodeId, + Uint32 aWaitState, + NdbApiSignal* aSignal, + Uint32 nodeSequence, + Uint32 *ret_conn_seq= 0); + + // Sets Restart GCI in Ndb object + void RestartGCI(int aRestartGCI); + + // Get block number of this NDBAPI object + int getBlockNumber(); + + /**************************************************************************** + * These are local service routines used by this class. + ***************************************************************************/ + + int createConIdleList(int aNrOfCon); + int createOpIdleList( int nrOfOp ); + + void freeOperation(); // Free the first idle operation. + void freeScanOperation(); // Free the first idle scan operation. + void freeIndexOperation(); // Free the first idle index operation. + void freeNdbCon(); // Free the first idle connection. + void freeSignal(); // Free the first idle signal + void freeRecAttr(); // Free the first idle receive attr obj + void freeNdbLabel(); // Free the first idle NdbLabel obj + void freeNdbBranch();// Free the first idle NdbBranch obj + void freeNdbSubroutine();// Free the first idle NdbSubroutine obj + void freeNdbCall(); // Free the first idle NdbCall obj + void freeNdbScanRec(); // Free the first idle NdbScanRec obj + void freeNdbBlob(); // Free the first etc + + NdbTransaction* getNdbCon(); // Get a connection from idle list + + /** + * Get a connected NdbTransaction to nodeId + * Returns NULL if none found + */ + NdbTransaction* getConnectedNdbTransaction(Uint32 nodeId); + + // Release and disconnect from DBTC a connection + // and seize it to theConIdleList + void releaseConnectToNdb (NdbTransaction*); + + // Release a connection to idle list + void releaseNdbCon (NdbTransaction*); + + int checkInitState(); // Check that we are initialized + void report_node_failure(Uint32 node_id); // Report Failed node + void report_node_failure_completed(Uint32 node_id); // Report Failed node(NF comp.) + + void checkFailedNode(); // Check for failed nodes + + int NDB_connect(); // Perform connect towards NDB Kernel + + // Release arrays of NdbTransaction pointers + void releaseTransactionArrays(); + + Uint32 pollCompleted(NdbTransaction** aCopyArray); + void sendPrepTrans(int forceSend); + void reportCallback(NdbTransaction** aCopyArray, Uint32 aNoOfComplTrans); + int poll_trans(int milliSecs, int noOfEventsToWaitFor, PollGuard *pg); + void waitCompletedTransactions(int milliSecs, int noOfEventsToWaitFor, + PollGuard *pg); + void completedTransaction(NdbTransaction* aTransaction); + void completedScanTransaction(NdbTransaction* aTransaction); + + void abortTransactionsAfterNodeFailure(Uint16 aNodeId); + + static + const char * externalizeTableName(const char * internalTableName, + bool fullyQualifiedNames); + const char * externalizeTableName(const char * internalTableName); + const BaseString internalize_table_name(const char * external_name) const; + + static + const char * externalizeIndexName(const char * internalIndexName, + bool fullyQualifiedNames); + const char * externalizeIndexName(const char * internalIndexName); + const BaseString old_internalize_index_name(const NdbTableImpl * table, + const char * external_name) const; + const BaseString internalize_index_name(const NdbTableImpl * table, + const char * external_name) const; + + static + const BaseString getDatabaseFromInternalName(const char * internalName); + static + const BaseString getSchemaFromInternalName(const char * internalName); + + void* int2void (Uint32 val); + NdbReceiver* void2rec (void* val); + NdbTransaction* void2con (void* val); + NdbOperation* void2rec_op (void* val); + NdbIndexOperation* void2rec_iop (void* val); + +/****************************************************************************** + * These are the private variables in this class. + *****************************************************************************/ + NdbTransaction** thePreparedTransactionsArray; + NdbTransaction** theSentTransactionsArray; + NdbTransaction** theCompletedTransactionsArray; + + Uint32 theNoOfPreparedTransactions; + Uint32 theNoOfSentTransactions; + Uint32 theNoOfCompletedTransactions; + Uint32 theRemainingStartTransactions; + Uint32 theMaxNoOfTransactions; + Uint32 theMinNoOfEventsToWakeUp; + + Uint32 theNextConnectNode; + + bool fullyQualifiedNames; + + + + class NdbImpl * theImpl; + class NdbDictionaryImpl* theDictionary; + class NdbEventBuffer* theEventBuffer; + + NdbTransaction* theTransactionList; + NdbTransaction** theConnectionArray; + + Uint32 theMyRef; // My block reference + Uint32 theNode; // The node number of our node + + Uint64 the_last_check_time; + Uint64 theFirstTransId; + // The tupleId is retrieved from DB + const NdbDictionary::Table *m_sys_tab_0; + + Uint32 theRestartGCI; // the Restart GCI used by DIHNDBTAMPER + + NdbError theError; + + Int32 theNdbBlockNumber; + + enum InitType { + NotConstructed, + NotInitialised, + StartingInit, + Initialised, + InitConfigError + } theInitState; + + NdbApiSignal* theCommitAckSignal; + + +#ifdef POORMANSPURIFY + int cfreeSignals; + int cnewSignals; + int cgetSignals; + int creleaseSignals; +#endif + + static void executeMessage(void*, NdbApiSignal *, + struct LinearSectionPtr ptr[3]); + static void statusMessage(void*, Uint32, bool, bool); +#ifdef VM_TRACE + void printState(const char* fmt, ...); +#endif +}; + +#endif diff --git a/storage/ndb/include/ndbapi/NdbApi.hpp b/storage/ndb/include/ndbapi/NdbApi.hpp new file mode 100644 index 00000000000..aed4d5efbd7 --- /dev/null +++ b/storage/ndb/include/ndbapi/NdbApi.hpp @@ -0,0 +1,35 @@ +/* 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 */ + +#ifndef NdbApi_H +#define NdbApi_H + +#include "ndb_init.h" +#include "ndb_cluster_connection.hpp" +#include "ndbapi_limits.h" +#include "Ndb.hpp" +#include "NdbTransaction.hpp" +#include "NdbOperation.hpp" +#include "NdbScanOperation.hpp" +#include "NdbIndexOperation.hpp" +#include "NdbIndexScanOperation.hpp" +#include "NdbScanFilter.hpp" +#include "NdbRecAttr.hpp" +#include "NdbDictionary.hpp" +#include "NdbEventOperation.hpp" +#include "NdbPool.hpp" +#include "NdbBlob.hpp" +#endif diff --git a/storage/ndb/include/ndbapi/NdbBlob.hpp b/storage/ndb/include/ndbapi/NdbBlob.hpp new file mode 100644 index 00000000000..e8944d684d3 --- /dev/null +++ b/storage/ndb/include/ndbapi/NdbBlob.hpp @@ -0,0 +1,410 @@ +/* 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 */ + +#ifndef NdbBlob_H +#define NdbBlob_H + +#include <ndb_types.h> +#include <NdbDictionary.hpp> +#include <NdbTransaction.hpp> +#include <NdbError.hpp> + +class Ndb; +class NdbTransaction; +class NdbOperation; +class NdbRecAttr; +class NdbTableImpl; +class NdbColumnImpl; +class NdbEventOperationImpl; + +/** + * @class NdbBlob + * @brief Blob handle + * + * Blob data is stored in 2 places: + * + * - "header" and "inline bytes" stored in the blob attribute + * - "blob parts" stored in a separate table NDB$BLOB_<tid>_<cid> + * + * Inline and part sizes can be set via NdbDictionary::Column methods + * when the table is created. + * + * NdbBlob is a blob handle. To access blob data, the handle must be + * created using NdbOperation::getBlobHandle in operation prepare phase. + * The handle has following states: + * + * - prepared: before the operation is executed + * - active: after execute or next result but before transaction commit + * - closed: after transaction commit + * - invalid: after rollback or transaction close + * + * NdbBlob supports 3 styles of data access: + * + * - in prepare phase, NdbBlob methods getValue and setValue are used to + * prepare a read or write of a blob value of known size + * + * - in prepare phase, setActiveHook is used to define a routine which + * is invoked as soon as the handle becomes active + * + * - in active phase, readData and writeData are used to read or write + * blob data of arbitrary size + * + * The styles can be applied in combination (in above order). + * + * Blob operations take effect at next transaction execute. In some + * cases NdbBlob is forced to do implicit executes. To avoid this, + * operate on complete blob parts. + * + * Use NdbTransaction::executePendingBlobOps to flush your reads and + * writes. It avoids execute penalty if nothing is pending. It is not + * needed after execute (obviously) or after next scan result. + * + * NdbBlob also supports reading post or pre blob data from events. The + * handle can be read after next event on main table has been retrieved. + * The data is available immediately. See NdbEventOperation. + * + * Non-void NdbBlob methods return -1 on error and 0 on success. Output + * parameters are used when necessary. + * + * Usage notes for different operation types: + * + * - insertTuple must use setValue if blob attribute is 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 + * + * - 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: + * + * - too many pending blob ops can blow up i/o buffers + * + * - table and its blob part tables are not created atomically + */ +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL +/** + * - there is no support for an asynchronous interface + */ +#endif + +class NdbBlob { +public: + /** + * State. + */ + enum State { + Idle = 0, + Prepared = 1, + Active = 2, + Closed = 3, + Invalid = 9 + }; + /** + * Get the state of a NdbBlob object. + */ + State getState(); + /** + * Returns -1 for normal statement based blob and 0/1 for event + * operation post/pre data blob. Always succeeds. + */ + void getVersion(int& version); + /** + * Inline blob header. + */ + struct Head { + Uint64 length; + }; + /** + * Prepare to read blob value. The value is available after execute. + * Use getNull() to check for NULL and getLength() to get the real length + * and to check for truncation. Sets current read/write position to + * after the data read. + */ + int getValue(void* data, Uint32 bytes); + /** + * Prepare to insert or update blob value. An existing longer blob + * value will be truncated. The data buffer must remain valid until + * execute. Sets current read/write position to after the data. Set + * data to null pointer (0) to create a NULL value. + */ + int setValue(const void* data, Uint32 bytes); + /** + * Callback for setActiveHook(). Invoked immediately when the prepared + * operation has been executed (but not committed). Any getValue() or + * setValue() is done first. The blob handle is active so readData or + * writeData() etc can be used to manipulate blob value. A user-defined + * argument is passed along. Returns non-zero on error. + */ + typedef int ActiveHook(NdbBlob* me, void* arg); + /** + * Define callback for blob handle activation. The queue of prepared + * operations will be executed in no commit mode up to this point and + * then the callback is invoked. + */ + int setActiveHook(ActiveHook* activeHook, void* arg); +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + int getDefined(int& isNull); + int getNull(bool& isNull); +#endif + /** + * Return -1, 0, 1 if blob is undefined, non-null, or null. For + * non-event blob, undefined causes a state error. + */ + int getNull(int& isNull); + /** + * Set blob to NULL. + */ + int setNull(); + /** + * Get current length in bytes. Use getNull to distinguish between + * length 0 blob and NULL blob. + */ + int getLength(Uint64& length); + /** + * Truncate blob to given length. Has no effect if the length is + * larger than current length. + */ + int truncate(Uint64 length = 0); + /** + * Get current read/write position. + */ + int getPos(Uint64& pos); + /** + * Set read/write position. Must be between 0 and current length. + * "Sparse blobs" are not supported. + */ + int setPos(Uint64 pos); + /** + * Read at current position and set new position to first byte after + * the data read. A read past blob end returns actual number of bytes + * read in the in/out bytes parameter. + */ + int readData(void* data, Uint32& bytes); + /** + * Write at current position and set new position to first byte after + * the data written. A write past blob end extends the blob value. + */ + int writeData(const void* data, Uint32 bytes); + /** + * Return the blob column. + */ + const NdbDictionary::Column* getColumn(); + /** + * Get blob parts table name. Useful only to test programs. + */ + static int getBlobTableName(char* btname, Ndb* anNdb, const char* tableName, const char* columnName); + /** + * Get blob event name. The blob event is created if the main event + * monitors the blob column. The name includes main event name. + */ + static int getBlobEventName(char* bename, Ndb* anNdb, const char* eventName, const char* columnName); + /** + * Return error object. The error may be blob specific or may 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; + /** + * Return info about all blobs in this operation. + * + * Get first blob in list. + */ + NdbBlob* blobsFirstBlob(); + /** + * Return info about all blobs in this operation. + * + * Get next blob in list. Initialize with blobsFirstBlob(). + */ + NdbBlob* blobsNextBlob(); + +private: +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + friend class Ndb; + friend class NdbTransaction; + friend class NdbOperation; + friend class NdbScanOperation; + friend class NdbDictionaryImpl; + friend class NdbResultSet; // atNextResult + friend class NdbEventBuffer; + friend class NdbEventOperationImpl; +#endif + // state + State theState; + void setState(State newState); + // quick and dirty support for events (consider subclassing) + int theEventBlobVersion; // -1=normal blob 0=post event 1=pre event + // define blob table + static void getBlobTableName(char* btname, const NdbTableImpl* t, const NdbColumnImpl* c); + static void getBlobTable(NdbTableImpl& bt, const NdbTableImpl* t, const NdbColumnImpl* c); + static void getBlobEventName(char* bename, const NdbEventImpl* e, const NdbColumnImpl* c); + static void getBlobEvent(NdbEventImpl& be, const NdbEventImpl* e, const NdbColumnImpl* c); + // ndb api stuff + Ndb* theNdb; + NdbTransaction* theNdbCon; + NdbOperation* theNdbOp; + NdbEventOperationImpl* theEventOp; + NdbEventOperationImpl* theBlobEventOp; + NdbRecAttr* theBlobEventPkRecAttr; + NdbRecAttr* theBlobEventDistRecAttr; + NdbRecAttr* theBlobEventPartRecAttr; + NdbRecAttr* theBlobEventDataRecAttr; + const NdbTableImpl* theTable; + const NdbTableImpl* theAccessTable; + const NdbTableImpl* theBlobTable; + const NdbColumnImpl* theColumn; + char theFillChar; + // sizes + Uint32 theInlineSize; + Uint32 thePartSize; + Uint32 theStripeSize; + // getValue/setValue + bool theGetFlag; + char* theGetBuf; + bool theSetFlag; + const char* theSetBuf; + Uint32 theGetSetBytes; + // pending ops + Uint8 thePendingBlobOps; + // activation callback + ActiveHook* theActiveHook; + void* theActiveHookArg; + // buffers + struct Buf { + char* data; + unsigned size; + unsigned maxsize; + Buf(); + ~Buf(); + void alloc(unsigned n); + void zerorest(); + void copyfrom(const Buf& src); + }; + Buf theKeyBuf; + Buf theAccessKeyBuf; + Buf thePackKeyBuf; + Buf theHeadInlineBuf; + Buf theHeadInlineCopyBuf; // for writeTuple + Buf thePartBuf; + Buf theBlobEventDataBuf; + Uint32 thePartNumber; // for event + Head* theHead; + char* theInlineData; + NdbRecAttr* theHeadInlineRecAttr; + NdbOperation* theHeadInlineReadOp; + bool theHeadInlineUpdateFlag; + // length and read/write position + int theNullFlag; + Uint64 theLength; + Uint64 thePos; + // errors + NdbError theError; + // for keeping in lists + NdbBlob* theNext; + // initialization + NdbBlob(Ndb*); + void init(); + void release(); + // classify operations + bool isTableOp(); + bool isIndexOp(); + bool isKeyOp(); + bool isReadOp(); + bool isInsertOp(); + bool isUpdateOp(); + bool isWriteOp(); + bool isDeleteOp(); + bool isScanOp(); + bool isReadOnlyOp(); + bool isTakeOverOp(); + // computations + Uint32 getPartNumber(Uint64 pos); + Uint32 getPartCount(); + Uint32 getDistKey(Uint32 part); + // pack / unpack + int packKeyValue(const NdbTableImpl* aTable, const Buf& srcBuf); + int unpackKeyValue(const NdbTableImpl* aTable, Buf& dstBuf); + // getters and setters + int getTableKeyValue(NdbOperation* anOp); + int setTableKeyValue(NdbOperation* anOp); + int setAccessKeyValue(NdbOperation* anOp); + int setPartKeyValue(NdbOperation* anOp, Uint32 part); + int getHeadInlineValue(NdbOperation* anOp); + void getHeadFromRecAttr(); + int setHeadInlineValue(NdbOperation* anOp); + // data operations + int readDataPrivate(char* buf, Uint32& bytes); + int writeDataPrivate(const char* buf, Uint32 bytes); + int readParts(char* buf, Uint32 part, Uint32 count); + int readTableParts(char* buf, Uint32 part, Uint32 count); + int readEventParts(char* buf, Uint32 part, Uint32 count); + int insertParts(const char* buf, Uint32 part, Uint32 count); + int updateParts(const char* buf, Uint32 part, Uint32 count); + int deleteParts(Uint32 part, Uint32 count); + int deletePartsUnknown(Uint32 part); + // pending ops + int executePendingBlobReads(); + int executePendingBlobWrites(); + // callbacks + int invokeActiveHook(); + // blob handle maintenance + int atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl* aColumn); + int atPrepare(NdbEventOperationImpl* anOp, NdbEventOperationImpl* aBlobOp, const NdbColumnImpl* aColumn, int version); + int prepareColumn(); + int preExecute(NdbTransaction::ExecType anExecType, bool& batch); + int postExecute(NdbTransaction::ExecType anExecType); + int preCommit(); + int atNextResult(); + int atNextEvent(); + // errors + void setErrorCode(int anErrorCode, bool invalidFlag = false); + void setErrorCode(NdbOperation* anOp, bool invalidFlag = false); + void setErrorCode(NdbTransaction* aCon, bool invalidFlag = false); + void setErrorCode(NdbEventOperationImpl* anOp, bool invalidFlag = false); +#ifdef VM_TRACE + int getOperationType() const; + friend class NdbOut& operator<<(NdbOut&, const NdbBlob&); +#endif + // list stuff + void next(NdbBlob* obj) { theNext= obj;} + NdbBlob* next() { return theNext;} + friend struct Ndb_free_list_t<NdbBlob>; +}; + +#endif diff --git a/storage/ndb/include/ndbapi/NdbDictionary.hpp b/storage/ndb/include/ndbapi/NdbDictionary.hpp new file mode 100644 index 00000000000..8d9ade2fb84 --- /dev/null +++ b/storage/ndb/include/ndbapi/NdbDictionary.hpp @@ -0,0 +1,1918 @@ +/* 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 */ + +#ifndef NdbDictionary_H +#define NdbDictionary_H + +#include <ndb_types.h> + +class Ndb; +struct charset_info_st; +typedef struct charset_info_st CHARSET_INFO; + +/** + * @class NdbDictionary + * @brief Data dictionary class + * + * The preferred and supported way to create and drop tables and indexes + * in ndb is through the + * MySQL Server (see MySQL reference Manual, section MySQL Cluster). + * + * Tables and indexes that are created directly through the + * NdbDictionary class + * can not be viewed from the MySQL Server. + * Dropping indexes directly via the NdbApi will cause inconsistencies + * if they were originally created from a MySQL Cluster. + * + * This class supports schema data enquiries such as: + * -# Enquiries about tables + * (Dictionary::getTable, Table::getNoOfColumns, + * Table::getPrimaryKey, and Table::getNoOfPrimaryKeys) + * -# Enquiries about indexes + * (Dictionary::getIndex, Index::getNoOfColumns, + * and Index::getColumn) + * + * This class supports schema data definition such as: + * -# Creating tables (Dictionary::createTable) and table columns + * -# Dropping tables (Dictionary::dropTable) + * -# Creating secondary indexes (Dictionary::createIndex) + * -# Dropping secondary indexes (Dictionary::dropIndex) + * + * NdbDictionary has several help (inner) classes to support this: + * -# NdbDictionary::Dictionary the dictionary handling dictionary objects + * -# NdbDictionary::Table for creating tables + * -# NdbDictionary::Column for creating table columns + * -# NdbDictionary::Index for creating secondary indexes + * + * See @ref ndbapi_simple_index.cpp for details of usage. + */ +class NdbDictionary { +public: + NdbDictionary() {} /* Remove gcc warning */ + /** + * @class Object + * @brief Meta information about a database object (a table, index, etc) + */ + class Object { + public: + Object() {} /* Remove gcc warning */ + virtual ~Object() {} /* Remove gcc warning */ + /** + * Status of object + */ + enum Status { + New, ///< The object only exist in memory and + ///< has not been created in the NDB Kernel + Changed, ///< The object has been modified in memory + ///< and has to be commited in NDB Kernel for + ///< changes to take effect + Retrieved, ///< The object exist and has been read + ///< into main memory from NDB Kernel + Invalid, ///< The object has been invalidated + ///< and should not be used + Altered ///< Table has been altered in NDB kernel + ///< but is still valid for usage + }; + + /** + * Get status of object + */ + virtual Status getObjectStatus() const = 0; + + /** + * Get version of object + */ + virtual int getObjectVersion() const = 0; + + virtual int getObjectId() const = 0; + + /** + * Object type + */ + enum Type { + TypeUndefined = 0, ///< Undefined + SystemTable = 1, ///< System table + UserTable = 2, ///< User table (may be temporary) + UniqueHashIndex = 3, ///< Unique un-ordered hash index + OrderedIndex = 6, ///< Non-unique ordered index + HashIndexTrigger = 7, ///< Index maintenance, internal + IndexTrigger = 8, ///< Index maintenance, internal + SubscriptionTrigger = 9,///< Backup or replication, internal + ReadOnlyConstraint = 10,///< Trigger, internal + Tablespace = 20, ///< Tablespace + LogfileGroup = 21, ///< Logfile group + Datafile = 22, ///< Datafile + Undofile = 23 ///< Undofile + }; + + /** + * Object state + */ + enum State { + StateUndefined = 0, ///< Undefined + StateOffline = 1, ///< Offline, not usable + StateBuilding = 2, ///< Building, not yet usable + StateDropping = 3, ///< Offlining or dropping, not usable + StateOnline = 4, ///< Online, usable + StateBackup = 5, ///< Online, being backuped, usable + StateBroken = 9 ///< Broken, should be dropped and re-created + }; + + /** + * Object store + */ + enum Store { + StoreUndefined = 0, ///< Undefined + StoreNotLogged = 1, ///< Object or data deleted on system restart + StorePermanent = 2 ///< Permanent. logged to disk + }; + + /** + * Type of fragmentation. + * + * This parameter specifies how data in the table or index will + * be distributed among the db nodes in the cluster.<br> + * The bigger the table the more number of fragments should be used. + * Note that all replicas count as same "fragment".<br> + * For a table, default is FragAllMedium. For a unique hash index, + * default is taken from underlying table and cannot currently + * be changed. + */ + enum FragmentType { + FragUndefined = 0, ///< Fragmentation type undefined or default + FragSingle = 1, ///< Only one fragment + FragAllSmall = 2, ///< One fragment per node, default + FragAllMedium = 3, ///< two fragments per node + FragAllLarge = 4, ///< Four fragments per node. + DistrKeyHash = 5, + DistrKeyLin = 6, + UserDefined = 7 + }; + }; + + class Dictionary; // Forward declaration + + class ObjectId : public Object + { + public: + ObjectId(); + virtual ~ObjectId(); + + /** + * Get status of object + */ + virtual Status getObjectStatus() const; + + /** + * Get version of object + */ + virtual int getObjectVersion() const; + + virtual int getObjectId() const; + + private: + friend class NdbDictObjectImpl; + class NdbDictObjectImpl & m_impl; + }; + + class Table; // forward declaration + class Tablespace; // forward declaration +// class NdbEventOperation; // forward declaration + + /** + * @class Column + * @brief Represents a column in an NDB Cluster table + * + * Each column has a type. The type of a column is determined by a number + * of type specifiers. + * The type specifiers are: + * - Builtin type + * - Array length or max length + * - Precision and scale (not used yet) + * - Character set for string types + * - Inline and part sizes for blobs + * + * Types in general correspond to MySQL types and their variants. + * Data formats are same as in MySQL. NDB API provides no support for + * constructing such formats. NDB kernel checks them however. + */ + class Column { + public: + /** + * The builtin column types + */ + enum Type { + Undefined = NDB_TYPE_UNDEFINED, ///< Undefined + Tinyint = NDB_TYPE_TINYINT, ///< 8 bit. 1 byte signed integer, can be used in array + Tinyunsigned = NDB_TYPE_TINYUNSIGNED, ///< 8 bit. 1 byte unsigned integer, can be used in array + Smallint = NDB_TYPE_SMALLINT, ///< 16 bit. 2 byte signed integer, can be used in array + Smallunsigned = NDB_TYPE_SMALLUNSIGNED, ///< 16 bit. 2 byte unsigned integer, can be used in array + Mediumint = NDB_TYPE_MEDIUMINT, ///< 24 bit. 3 byte signed integer, can be used in array + Mediumunsigned = NDB_TYPE_MEDIUMUNSIGNED,///< 24 bit. 3 byte unsigned integer, can be used in array + Int = NDB_TYPE_INT, ///< 32 bit. 4 byte signed integer, can be used in array + Unsigned = NDB_TYPE_UNSIGNED, ///< 32 bit. 4 byte unsigned integer, can be used in array + Bigint = NDB_TYPE_BIGINT, ///< 64 bit. 8 byte signed integer, can be used in array + Bigunsigned = NDB_TYPE_BIGUNSIGNED, ///< 64 Bit. 8 byte signed integer, can be used in array + Float = NDB_TYPE_FLOAT, ///< 32-bit float. 4 bytes float, can be used in array + Double = NDB_TYPE_DOUBLE, ///< 64-bit float. 8 byte float, can be used in array + Olddecimal = NDB_TYPE_OLDDECIMAL, ///< MySQL < 5.0 signed decimal, Precision, Scale + Olddecimalunsigned = NDB_TYPE_OLDDECIMALUNSIGNED, + Decimal = NDB_TYPE_DECIMAL, ///< MySQL >= 5.0 signed decimal, Precision, Scale + Decimalunsigned = NDB_TYPE_DECIMALUNSIGNED, + Char = NDB_TYPE_CHAR, ///< Len. A fixed array of 1-byte chars + Varchar = NDB_TYPE_VARCHAR, ///< Length bytes: 1, Max: 255 + Binary = NDB_TYPE_BINARY, ///< Len + Varbinary = NDB_TYPE_VARBINARY, ///< Length bytes: 1, Max: 255 + Datetime = NDB_TYPE_DATETIME, ///< Precision down to 1 sec (sizeof(Datetime) == 8 bytes ) + Date = NDB_TYPE_DATE, ///< Precision down to 1 day(sizeof(Date) == 4 bytes ) + Blob = NDB_TYPE_BLOB, ///< Binary large object (see NdbBlob) + Text = NDB_TYPE_TEXT, ///< Text blob + Bit = NDB_TYPE_BIT, ///< Bit, length specifies no of bits + Longvarchar = NDB_TYPE_LONGVARCHAR, ///< Length bytes: 2, little-endian + Longvarbinary = NDB_TYPE_LONGVARBINARY, ///< Length bytes: 2, little-endian + Time = NDB_TYPE_TIME, ///< Time without date + Year = NDB_TYPE_YEAR, ///< Year 1901-2155 (1 byte) + Timestamp = NDB_TYPE_TIMESTAMP ///< Unix time + }; + + /* + * Array type specifies internal attribute format. + * + * - ArrayTypeFixed is stored as fixed number of bytes. This type + * is fastest to access but can waste space. + * + * - ArrayTypeVar is stored as variable number of bytes with a fixed + * overhead of 2 bytes. + * + * Default is ArrayTypeVar for Var* types and ArrayTypeFixed for + * others. The default is normally ok. + */ + enum ArrayType { + ArrayTypeFixed = NDB_ARRAYTYPE_FIXED, // 0 length bytes + ArrayTypeShortVar = NDB_ARRAYTYPE_SHORT_VAR, // 1 length bytes + ArrayTypeMediumVar = NDB_ARRAYTYPE_MEDIUM_VAR // 2 length bytes + }; + + /* + * Storage type specifies whether attribute is stored in memory or + * on disk. Default is memory. Disk attributes are potentially + * much slower to access and cannot be indexed in version 5.1. + */ + enum StorageType { + StorageTypeMemory = NDB_STORAGETYPE_MEMORY, + StorageTypeDisk = NDB_STORAGETYPE_DISK + }; + + /** + * @name General + * @{ + */ + + /** + * Get name of column + * @return Name of the column + */ + const char* getName() const; + + /** + * Get if the column is nullable or not + */ + bool getNullable() const; + + /** + * Check if column is part of primary key + */ + bool getPrimaryKey() const; + + /** + * Get number of column (horizontal position within table) + */ + int getColumnNo() const; + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + int getAttrId() const; +#endif + + /** + * Check if column is equal to some other column + * @param column Column to compare with + * @return true if column is equal to some other column otherwise false. + */ + bool equal(const Column& column) const; + + + /** @} *******************************************************************/ + /** + * @name Get Type Specifiers + * @{ + */ + + /** + * Get type of column + */ + Type getType() const; + + /** + * Get precision of column. + * @note Only applicable for decimal types + */ + int getPrecision() const; + + /** + * Get scale of column. + * @note Only applicable for decimal types + */ + int getScale() const; + + /** + * Get length for column + * Array length for column or max length for variable length arrays. + */ + int getLength() const; + + /** + * For Char or Varchar or Text, get MySQL CHARSET_INFO. This + * specifies both character set and collation. See get_charset() + * etc in MySQL. (The cs is not "const" in MySQL). + */ + CHARSET_INFO* getCharset() const; + + + /** + * For blob, get "inline size" i.e. number of initial bytes + * to store in table's blob attribute. This part is normally in + * main memory and can be indexed and interpreted. + */ + int getInlineSize() const; + + /** + * For blob, get "part size" i.e. number of bytes to store in + * each tuple of the "blob table". Can be set to zero to omit parts + * and to allow only inline bytes ("tinyblob"). + */ + int getPartSize() const; + + /** + * For blob, set or get "stripe size" i.e. number of consecutive + * <em>parts</em> to store in each node group. + */ + int getStripeSize() const; + + /** + * Get size of element + */ + int getSize() const; + + /** + * Check if column is part of partition key + * + * A <em>partition key</em> is a set of attributes which are used + * to distribute the tuples onto the NDB nodes. + * The partition key uses the NDB Cluster hashing function. + * + * An example where this is useful is TPC-C where it might be + * good to use the warehouse id and district id as the partition key. + * This would place all data for a specific district and warehouse + * in the same database node. + * + * Locally in the fragments the full primary key + * will still be used with the hashing algorithm. + * + * @return true then the column is part of + * the partition key. + */ + bool getPartitionKey() const; +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + inline bool getDistributionKey() const { return getPartitionKey(); }; +#endif + + ArrayType getArrayType() const; + StorageType getStorageType() const; + + /** @} *******************************************************************/ + + + /** + * @name Column creation + * @{ + * + * These operations should normally not be performed in an NbdApi program + * as results will not be visable in the MySQL Server + * + */ + + /** + * Constructor + * @param name Name of column + */ + Column(const char * name = ""); + /** + * Copy constructor + * @param column Column to be copied + */ + Column(const Column& column); + ~Column(); + + /** + * Set name of column + * @param name Name of the column + */ + void setName(const char * name); + + /** + * Set whether column is nullable or not + */ + void setNullable(bool); + + /** + * Set that column is part of primary key + */ + void setPrimaryKey(bool); + + /** + * Set type of column + * @param type Type of column + * + * @note setType resets <em>all</em> column attributes + * to (type dependent) defaults and should be the first + * method to call. Default type is Unsigned. + */ + void setType(Type type); + + /** + * Set precision of column. + * @note Only applicable for decimal types + */ + void setPrecision(int); + + /** + * Set scale of column. + * @note Only applicable for decimal types + */ + void setScale(int); + + /** + * Set length for column + * Array length for column or max length for variable length arrays. + */ + void setLength(int length); + + /** + * For Char or Varchar or Text, get MySQL CHARSET_INFO. This + * specifies both character set and collation. See get_charset() + * etc in MySQL. (The cs is not "const" in MySQL). + */ + void setCharset(CHARSET_INFO* cs); + + /** + * For blob, get "inline size" i.e. number of initial bytes + * to store in table's blob attribute. This part is normally in + * main memory and can be indexed and interpreted. + */ + void setInlineSize(int size); + + /** + * For blob, get "part size" i.e. number of bytes to store in + * each tuple of the "blob table". Can be set to zero to omit parts + * and to allow only inline bytes ("tinyblob"). + */ + void setPartSize(int size); + + /** + * For blob, get "stripe size" i.e. number of consecutive + * <em>parts</em> to store in each node group. + */ + void setStripeSize(int size); + + /** + * Set partition key + * @see getPartitionKey + * + * @param enable If set to true, then the column will be part of + * the partition key. + */ + void setPartitionKey(bool enable); +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + inline void setDistributionKey(bool enable) + { setPartitionKey(enable); }; +#endif + + void setArrayType(ArrayType type); + void setStorageType(StorageType type); + + /** @} *******************************************************************/ + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + const Table * getBlobTable() const; + + void setAutoIncrement(bool); + bool getAutoIncrement() const; + void setAutoIncrementInitialValue(Uint64 val); + void setDefaultValue(const char*); + const char* getDefaultValue() const; + + static const Column * FRAGMENT; + static const Column * FRAGMENT_FIXED_MEMORY; + static const Column * FRAGMENT_VARSIZED_MEMORY; + static const Column * ROW_COUNT; + static const Column * COMMIT_COUNT; + static const Column * ROW_SIZE; + static const Column * RANGE_NO; + static const Column * DISK_REF; + static const Column * RECORDS_IN_RANGE; + static const Column * ROWID; + static const Column * ROW_GCI; + + int getSizeInBytes() const; +#endif + + private: +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + friend class NdbRecAttr; + friend class NdbColumnImpl; +#endif + class NdbColumnImpl & m_impl; + Column(NdbColumnImpl&); + Column& operator=(const Column&); + }; + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + /** + * ??? + */ + typedef Column Attribute; +#endif + + /** + * @brief Represents a table in NDB Cluster + * + * <em>TableSize</em><br> + * When calculating the data storage one should add the size of all + * attributes (each attributeconsumes at least 4 bytes) and also an overhead + * of 12 byte. Variable size attributes (not supported yet) will have a + * size of 12 bytes plus the actual data storage parts where there is an + * additional overhead based on the size of the variable part.<br> + * An example table with 5 attributes: + * one 64 bit attribute, one 32 bit attribute, + * two 16 bit attributes and one array of 64 8 bits. + * This table will consume + * 12 (overhead) + 8 + 4 + 2*4 (4 is minimum) + 64 = 96 bytes per record. + * Additionally an overhead of about 2 % as page headers and waste should + * be allocated. Thus, 1 million records should consume 96 MBytes + * plus the overhead 2 MByte and rounded up to 100 000 kBytes.<br> + * + */ + class Table : public Object { + public: + /** + * @name General + * @{ + */ + + /** + * Get table name + */ + const char * getName() const; + + /** + * Get table id + */ + int getTableId() const; + + /** + * Get column definition via name. + * @return null if none existing name + */ + const Column* getColumn(const char * name) const; + + /** + * Get column definition via index in table. + * @return null if none existing name + */ + Column* getColumn(const int attributeId); + + /** + * Get column definition via name. + * @return null if none existing name + */ + Column* getColumn(const char * name); + + /** + * Get column definition via index in table. + * @return null if none existing name + */ + const Column* getColumn(const int attributeId) const; + + /** @} *******************************************************************/ + /** + * @name Storage + * @{ + */ + + /** + * If set to false, then the table is a temporary + * table and is not logged to disk. + * + * In case of a system restart the table will still + * be defined and exist but will be empty. + * Thus no checkpointing and no logging is performed on the table. + * + * The default value is true and indicates a normal table + * with full checkpointing and logging activated. + */ + bool getLogging() const; + + /** + * Get fragmentation type + */ + FragmentType getFragmentType() const; + + /** + * Get KValue (Hash parameter.) + * Only allowed value is 6. + * Later implementations might add flexibility in this parameter. + */ + int getKValue() const; + + /** + * Get MinLoadFactor (Hash parameter.) + * This value specifies the load factor when starting to shrink + * the hash table. + * It must be smaller than MaxLoadFactor. + * Both these factors are given in percentage. + */ + int getMinLoadFactor() const; + + /** + * Get MaxLoadFactor (Hash parameter.) + * This value specifies the load factor when starting to split + * the containers in the local hash tables. + * 100 is the maximum which will optimize memory usage. + * A lower figure will store less information in each container and thus + * find the key faster but consume more memory. + */ + int getMaxLoadFactor() const; + + /** @} *******************************************************************/ + /** + * @name Other + * @{ + */ + + /** + * Get number of columns in the table + */ + int getNoOfColumns() const; + + /** + * Get number of primary keys in the table + */ + int getNoOfPrimaryKeys() const; + + /** + * Get name of primary key + */ + const char* getPrimaryKey(int no) const; + + /** + * Check if table is equal to some other table + */ + bool equal(const Table&) const; + + /** + * Get frm file stored with this table + */ + const void* getFrmData() const; + Uint32 getFrmLength() const; + + /** + * Get Fragment Data (id, state and node group) + */ + const void *getFragmentData() const; + Uint32 getFragmentDataLen() const; + + /** + * Get Range or List Array (value, partition) + */ + const void *getRangeListData() const; + Uint32 getRangeListDataLen() const; + + /** + * Get Tablespace Data (id, version) + */ + const void *getTablespaceData() const; + Uint32 getTablespaceDataLen() const; + + /** @} *******************************************************************/ + + /** + * @name Table creation + * @{ + * + * These methods should normally not be used in an application as + * the result is not accessible from the MySQL Server + * + */ + + /** + * Constructor + * @param name Name of table + */ + Table(const char * name = ""); + + /** + * Copy constructor + * @param table Table to be copied + */ + Table(const Table& table); + virtual ~Table(); + + /** + * Assignment operator, deep copy + * @param table Table to be copied + */ + Table& operator=(const Table& table); + + /** + * Name of table + * @param name Name of table + */ + void setName(const char * name); + + /** + * Add a column definition to a table + * @note creates a copy + */ + void addColumn(const Column &); + + /** + * @see NdbDictionary::Table::getLogging. + */ + void setLogging(bool); + + /** + * Set/Get Linear Hash Flag + */ + void setLinearFlag(Uint32 flag); + bool getLinearFlag() const; + + /** + * Set fragment count + */ + void setFragmentCount(Uint32); + + /** + * Get fragment count + */ + Uint32 getFragmentCount() const; + + /** + * Set fragmentation type + */ + void setFragmentType(FragmentType); + + /** + * Set KValue (Hash parameter.) + * Only allowed value is 6. + * Later implementations might add flexibility in this parameter. + */ + void setKValue(int kValue); + + /** + * Set MinLoadFactor (Hash parameter.) + * This value specifies the load factor when starting to shrink + * the hash table. + * It must be smaller than MaxLoadFactor. + * Both these factors are given in percentage. + */ + void setMinLoadFactor(int); + + /** + * Set MaxLoadFactor (Hash parameter.) + * This value specifies the load factor when starting to split + * the containers in the local hash tables. + * 100 is the maximum which will optimize memory usage. + * A lower figure will store less information in each container and thus + * find the key faster but consume more memory. + */ + void setMaxLoadFactor(int); + + void setTablespace(const char * name); + void setTablespace(const class Tablespace &); + const char * getTablespace() const; + bool getTablespace(Uint32 *id= 0, Uint32 *version= 0) const; + + /** + * Get table object type + */ + Object::Type getObjectType() const; + + /** + * Get object status + */ + virtual Object::Status getObjectStatus() const; + void setStatusInvalid() const; + + /** + * Get object version + */ + virtual int getObjectVersion() const; + + /** + * Set/Get indicator if default number of partitions is used in table. + */ + void setDefaultNoPartitionsFlag(Uint32 indicator); + Uint32 getDefaultNoPartitionsFlag() const; + + /** + * Get object id + */ + virtual int getObjectId() const; + + /** + * Set frm file to store with this table + */ + void setFrm(const void* data, Uint32 len); + + /** + * Set array of fragment information containing + * Fragment Identity + * Node group identity + * Fragment State + */ + void setFragmentData(const void* data, Uint32 len); + + /** + * Set/Get tablespace names per fragment + */ + void setTablespaceNames(const void* data, Uint32 len); + const void *getTablespaceNames(); + Uint32 getTablespaceNamesLen() const; + + /** + * Set tablespace information per fragment + * Contains a tablespace id and a tablespace version + */ + void setTablespaceData(const void* data, Uint32 len); + + /** + * Set array of information mapping range values and list values + * to fragments. This is essentially a sorted map consisting of + * pairs of value, fragment identity. For range partitions there is + * one pair per fragment. For list partitions it could be any number + * of pairs, at least as many as there are fragments. + */ + void setRangeListData(const void* data, Uint32 len); + + /** + * Set table object type + */ + void setObjectType(Object::Type type); + + /** + * Set/Get Maximum number of rows in table (only used to calculate + * number of partitions). + */ + void setMaxRows(Uint64 maxRows); + Uint64 getMaxRows() const; + + /** + * Set/Get Minimum number of rows in table (only used to calculate + * number of partitions). + */ + void setMinRows(Uint64 minRows); + Uint64 getMinRows() const; + + /** @} *******************************************************************/ + + /** + * + */ + void setRowGCIIndicator(bool value); + bool getRowGCIIndicator() const; + + void setRowChecksumIndicator(bool value); + bool getRowChecksumIndicator() const; + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + const char *getMysqlName() const; + + void setStoredTable(bool x) { setLogging(x); } + bool getStoredTable() const { return getLogging(); } + + int getRowSizeInBytes() const ; + int createTableInDb(Ndb*, bool existingEqualIsOk = true) const ; + + int getReplicaCount() const ; + + bool getTemporary(); + void setTemporary(bool); + + /** + * Check if any of column in bitmaps are disk columns + * returns bitmap of different columns + * bit 0 = atleast 1 pk column is set + * bit 1 = atleast 1 disk column set + * bit 2 = atleast 1 non disk column set + * passing NULL pointer will equal to bitmap with all columns set + */ + int checkColumns(const Uint32* bitmap, unsigned len_in_bytes) const; +#endif + + // these 2 are not de-doxygenated + + /** + * This method is not needed in normal usage. + * + * Compute aggregate data on table being defined. Required for + * aggregate methods such as getNoOfPrimaryKeys() to work before + * table has been created and retrieved via getTable(). + * + * May adjust some column flags. If no PK is so far marked as + * distribution key then all PK's will be marked. + * + * Returns 0 on success. Returns -1 and sets error if an + * inconsistency is detected. + */ + int aggregate(struct NdbError& error); + + /** + * This method is not needed in normal usage. + * + * Validate new table definition before create. Does aggregate() + * and additional checks. There may still be errors which are + * detected only by NDB kernel at create table. + * + * Create table and retrieve table do validate() automatically. + * + * Returns 0 on success. Returns -1 and sets error if an + * inconsistency is detected. + */ + int validate(struct NdbError& error); + + private: +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + friend class Ndb; + friend class NdbDictionaryImpl; + friend class NdbTableImpl; + friend class NdbEventOperationImpl; +#endif + class NdbTableImpl & m_impl; + Table(NdbTableImpl&); + }; + + /** + * @class Index + * @brief Represents an index in an NDB Cluster + */ + class Index : public Object { + public: + + /** + * @name Getting Index properties + * @{ + */ + + /** + * Get the name of an index + */ + const char * getName() const; + + /** + * Get the name of the table being indexed + */ + const char * getTable() const; + + /** + * Get the number of columns in the index + */ + unsigned getNoOfColumns() const; + +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + /** + * Get the number of columns in the index + * Depricated, use getNoOfColumns instead. + */ + int getNoOfIndexColumns() const; +#endif + + /** + * Get a specific column in the index + */ + const Column * getColumn(unsigned no) const ; + +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + /** + * Get a specific column name in the index + * Depricated, use getColumn instead. + */ + const char * getIndexColumn(int no) const ; +#endif + + /** + * Represents type of index + */ + enum Type { + Undefined = 0, ///< Undefined object type (initial value) + UniqueHashIndex = 3, ///< Unique un-ordered hash index + ///< (only one currently supported) + OrderedIndex = 6 ///< Non-unique ordered index + }; + + /** + * Get index type of the index + */ + Type getType() const; + + /** + * Check if index is set to be stored on disk + * + * @return if true then logging id enabled + * + * @note Non-logged indexes are rebuilt at system restart. + * @note Ordered index does not currently support logging. + */ + bool getLogging() const; + + /** + * Get object status + */ + virtual Object::Status getObjectStatus() const; + + /** + * Get object version + */ + virtual int getObjectVersion() const; + + /** + * Get object id + */ + virtual int getObjectId() const; + + /** @} *******************************************************************/ + + /** + * @name Index creation + * @{ + * + * These methods should normally not be used in an application as + * the result will not be visible from the MySQL Server + * + */ + + /** + * Constructor + * @param name Name of index + */ + Index(const char * name = ""); + virtual ~Index(); + + /** + * Set the name of an index + */ + void setName(const char * name); + + /** + * Define the name of the table to be indexed + */ + void setTable(const char * name); + + /** + * Add a column to the index definition + * Note that the order of columns will be in + * the order they are added (only matters for ordered indexes). + */ + void addColumn(const Column & c); + + /** + * Add a column name to the index definition + * Note that the order of indexes will be in + * the order they are added (only matters for ordered indexes). + */ + void addColumnName(const char * name); + +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + /** + * Add a column name to the index definition + * Note that the order of indexes will be in + * the order they are added (only matters for ordered indexes). + * Depricated, use addColumnName instead. + */ + void addIndexColumn(const char * name); +#endif + + /** + * Add several column names to the index definition + * Note that the order of indexes will be in + * the order they are added (only matters for ordered indexes). + */ + void addColumnNames(unsigned noOfNames, const char ** names); + +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + /** + * Add several column names to the index definition + * Note that the order of indexes will be in + * the order they are added (only matters for ordered indexes). + * Depricated, use addColumnNames instead. + */ + void addIndexColumns(int noOfNames, const char ** names); +#endif + + /** + * Set index type of the index + */ + void setType(Type type); + + /** + * Enable/Disable index storage on disk + * + * @param enable If enable is set to true, then logging becomes enabled + * + * @see NdbDictionary::Index::getLogging + */ + void setLogging(bool enable); + +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + void setStoredIndex(bool x) { setLogging(x); } + bool getStoredIndex() const { return getLogging(); } + + bool getTemporary(); + void setTemporary(bool); +#endif + + /** @} *******************************************************************/ + + private: +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + friend class NdbIndexImpl; + friend class NdbIndexStat; +#endif + class NdbIndexImpl & m_impl; + Index(NdbIndexImpl&); + }; + + /** + * @brief Represents an Event in NDB Cluster + * + */ + class Event : public Object { + public: + /** + * Specifies the type of database operations an Event listens to + */ +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + /** TableEvent must match 1 << TriggerEvent */ +#endif + enum TableEvent { + TE_INSERT =1<<0, ///< Insert event on table + TE_DELETE =1<<1, ///< Delete event on table + TE_UPDATE =1<<2, ///< Update event on table +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + TE_SCAN =1<<3, ///< Scan event on table + TE_FIRST_NON_DATA_EVENT =1<<4, +#endif + TE_DROP =1<<4, ///< Drop of table + TE_ALTER =1<<5, ///< Alter of table + TE_CREATE =1<<6, ///< Create of table + TE_GCP_COMPLETE=1<<7, ///< GCP is complete + TE_CLUSTER_FAILURE=1<<8, ///< Cluster is unavailable + TE_STOP =1<<9, ///< Stop of event operation + TE_NODE_FAILURE=1<<10, ///< Node failed + TE_SUBSCRIBE =1<<11, ///< Node subscribes + TE_UNSUBSCRIBE =1<<12, ///< Node unsubscribes + TE_ALL=0xFFFF ///< Any/all event on table (not relevant when + ///< events are received) + }; +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + enum _TableEvent { + _TE_INSERT=0, + _TE_DELETE=1, + _TE_UPDATE=2, + _TE_SCAN=3, + _TE_FIRST_NON_DATA_EVENT=4, + _TE_DROP=4, + _TE_ALTER=5, + _TE_CREATE=6, + _TE_GCP_COMPLETE=7, + _TE_CLUSTER_FAILURE=8, + _TE_STOP=9, + _TE_NODE_FAILURE=10, + _TE_SUBSCRIBE=11, + _TE_UNSUBSCRIBE=12, + _TE_NUL=13, // internal (e.g. INS o DEL within same GCI) + _TE_ACTIVE=14 // internal (node becomes active) + }; +#endif + /** + * Specifies the durability of an event + * (future version may supply other types) + */ + enum EventDurability { + ED_UNDEFINED +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + = 0 +#endif +#if 0 // not supported + ,ED_SESSION = 1, + // Only this API can use it + // and it's deleted after api has disconnected or ndb has restarted + + ED_TEMPORARY = 2 + // All API's can use it, + // But's its removed when ndb is restarted +#endif + ,ED_PERMANENT ///< All API's can use it. + ///< It's still defined after a cluster system restart +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + = 3 +#endif + }; + + /** + * Specifies reporting options for table events + */ + enum EventReport { + ER_UPDATED = 0, + ER_ALL = 1, // except not-updated blob inlines + ER_SUBSCRIBE = 2 + }; + + /** + * Constructor + * @param name Name of event + */ + Event(const char *name); + /** + * Constructor + * @param name Name of event + * @param table Reference retrieved from NdbDictionary + */ + Event(const char *name, const NdbDictionary::Table& table); + virtual ~Event(); + /** + * Set unique identifier for the event + */ + void setName(const char *name); + /** + * Get unique identifier for the event + */ + const char *getName() const; + /** + * Get table that the event is defined on + * + * @return pointer to table or NULL if no table has been defined + */ + const NdbDictionary::Table * getTable() const; + /** + * Define table on which events should be detected + * + * @note calling this method will default to detection + * of events on all columns. Calling subsequent + * addEventColumn calls will override this. + * + * @param table reference retrieved from NdbDictionary + */ + void setTable(const NdbDictionary::Table& table); + /** + * Set table for which events should be detected + * + * @note preferred way is using setTable(const NdbDictionary::Table&) + * or constructor with table object parameter + */ + void setTable(const char *tableName); + /** + * Get table name for events + * + * @return table name + */ + const char* getTableName() const; + /** + * Add type of event that should be detected + */ + void addTableEvent(const TableEvent te); + /** + * Check if a specific table event will be detected + */ + bool getTableEvent(const TableEvent te) const; + /** + * Set durability of the event + */ + void setDurability(EventDurability); + /** + * Get durability of the event + */ + EventDurability getDurability() const; + /** + * Set report option of the event + */ + void setReport(EventReport); + /** + * Get report option of the event + */ + EventReport getReport() const; +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + void addColumn(const Column &c); +#endif + /** + * Add a column on which events should be detected + * + * @param attrId Column id + * + * @note errors will mot be detected until createEvent() is called + */ + void addEventColumn(unsigned attrId); + /** + * Add a column on which events should be detected + * + * @param columnName Column name + * + * @note errors will not be detected until createEvent() is called + */ + void addEventColumn(const char * columnName); + /** + * Add several columns on which events should be detected + * + * @param n Number of columns + * @param columnNames Column names + * + * @note errors will mot be detected until + * NdbDictionary::Dictionary::createEvent() is called + */ + void addEventColumns(int n, const char ** columnNames); + + /** + * Get no of columns defined in an Event + * + * @return Number of columns, -1 on error + */ + int getNoOfEventColumns() const; + + /** + * Get a specific column in the event + */ + const Column * getEventColumn(unsigned no) const; + + /** + * The merge events flag is false by default. Setting it true + * implies that events are merged in following ways: + * + * - for given NdbEventOperation associated with this event, + * events on same PK within same GCI are merged into single event + * + * - a blob table event is created for each blob attribute + * and blob events are handled as part of main table events + * + * - blob post/pre data from the blob part events can be read + * via NdbBlob methods as a single value + * + * NOTE: Currently this flag is not inherited by NdbEventOperation + * and must be set on NdbEventOperation explicitly. + */ + void mergeEvents(bool flag); + + /** + * Get object status + */ + virtual Object::Status getObjectStatus() const; + + /** + * Get object version + */ + virtual int getObjectVersion() const; + + /** + * Get object id + */ + virtual int getObjectId() const; + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + void print(); +#endif + + private: +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + friend class NdbEventImpl; + friend class NdbEventOperationImpl; +#endif + class NdbEventImpl & m_impl; + Event(NdbEventImpl&); + }; + + struct AutoGrowSpecification { + Uint32 min_free; + Uint64 max_size; + Uint64 file_size; + const char * filename_pattern; + }; + + /** + * @class LogfileGroup + */ + class LogfileGroup : public Object { + public: + LogfileGroup(); + LogfileGroup(const LogfileGroup&); + virtual ~LogfileGroup(); + + void setName(const char * name); + const char* getName() const; + + void setUndoBufferSize(Uint32 sz); + Uint32 getUndoBufferSize() const; + + void setAutoGrowSpecification(const AutoGrowSpecification&); + const AutoGrowSpecification& getAutoGrowSpecification() const; + + Uint64 getUndoFreeWords() const; + + /** + * Get object status + */ + virtual Object::Status getObjectStatus() const; + + /** + * Get object version + */ + virtual int getObjectVersion() const; + + /** + * Get object id + */ + virtual int getObjectId() const; + + private: + friend class NdbDictionaryImpl; + friend class NdbLogfileGroupImpl; + class NdbLogfileGroupImpl & m_impl; + LogfileGroup(NdbLogfileGroupImpl&); + }; + + /** + * @class Tablespace + */ + class Tablespace : public Object { + public: + Tablespace(); + Tablespace(const Tablespace&); + virtual ~Tablespace(); + + void setName(const char * name); + const char* getName() const; + + void setExtentSize(Uint32 sz); + Uint32 getExtentSize() const; + + void setAutoGrowSpecification(const AutoGrowSpecification&); + const AutoGrowSpecification& getAutoGrowSpecification() const; + + void setDefaultLogfileGroup(const char * name); + void setDefaultLogfileGroup(const class LogfileGroup&); + + const char * getDefaultLogfileGroup() const; + Uint32 getDefaultLogfileGroupId() const; + + /** + * Get object status + */ + virtual Object::Status getObjectStatus() const; + + /** + * Get object version + */ + virtual int getObjectVersion() const; + + /** + * Get object id + */ + virtual int getObjectId() const; + + private: + friend class NdbTablespaceImpl; + class NdbTablespaceImpl & m_impl; + Tablespace(NdbTablespaceImpl&); + }; + + class Datafile : public Object { + public: + Datafile(); + Datafile(const Datafile&); + virtual ~Datafile(); + + void setPath(const char * name); + const char* getPath() const; + + void setSize(Uint64); + Uint64 getSize() const; + Uint64 getFree() const; + + void setTablespace(const char * name); + void setTablespace(const class Tablespace &); + const char * getTablespace() const; + void getTablespaceId(ObjectId * dst) const; + + void setNode(Uint32 nodeId); + Uint32 getNode() const; + + Uint32 getFileNo() const; + + /** + * Get object status + */ + virtual Object::Status getObjectStatus() const; + + /** + * Get object version + */ + virtual int getObjectVersion() const; + + /** + * Get object id + */ + virtual int getObjectId() const; + + private: + friend class NdbDatafileImpl; + class NdbDatafileImpl & m_impl; + Datafile(NdbDatafileImpl&); + }; + + class Undofile : public Object { + public: + Undofile(); + Undofile(const Undofile&); + virtual ~Undofile(); + + void setPath(const char * path); + const char* getPath() const; + + void setSize(Uint64); + Uint64 getSize() const; + + void setLogfileGroup(const char * name); + void setLogfileGroup(const class LogfileGroup &); + const char * getLogfileGroup() const; + void getLogfileGroupId(ObjectId * dst) const; + + void setNode(Uint32 nodeId); + Uint32 getNode() const; + + Uint32 getFileNo() const; + + /** + * Get object status + */ + virtual Object::Status getObjectStatus() const; + + /** + * Get object version + */ + virtual int getObjectVersion() const; + + /** + * Get object id + */ + virtual int getObjectId() const; + + private: + friend class NdbUndofileImpl; + class NdbUndofileImpl & m_impl; + Undofile(NdbUndofileImpl&); + }; + + /** + * @class Dictionary + * @brief Dictionary for defining and retreiving meta data + */ + class Dictionary { + public: + /** + * @class List + * @brief Structure for retrieving lists of object names + */ + struct List { + /** + * @struct Element + * @brief Object to be stored in an NdbDictionary::Dictionary::List + */ + struct Element { + unsigned id; ///< Id of object + Object::Type type; ///< Type of object + Object::State state; ///< State of object + Object::Store store; ///< How object is logged + Uint32 temp; ///< Temporary status of object + char * database; ///< In what database the object resides + char * schema; ///< What schema the object is defined in + char * name; ///< Name of object + Element() : + id(0), + type(Object::TypeUndefined), + state(Object::StateUndefined), + store(Object::StoreUndefined), + temp(NDB_TEMP_TAB_PERMANENT), + database(0), + schema(0), + name(0) { + } + }; + unsigned count; ///< Number of elements in list + Element * elements; ///< Pointer to array of elements + List() : count(0), elements(0) {} + ~List() { + if (elements != 0) { + for (unsigned i = 0; i < count; i++) { + delete[] elements[i].database; + delete[] elements[i].schema; + delete[] elements[i].name; + elements[i].name = 0; + } + delete[] elements; + count = 0; + elements = 0; + } + } + }; + + /** + * @name General + * @{ + */ + + /** + * Fetch list of all objects, optionally restricted to given type. + * + * @param list List of objects returned in the dictionary + * @param type Restrict returned list to only contain objects of + * this type + * + * @return -1 if error. + * + */ + int listObjects(List & list, Object::Type type = Object::TypeUndefined); + int listObjects(List & list, + Object::Type type = Object::TypeUndefined) const; + + /** + * Get the latest error + * + * @return Error object. + */ + const struct NdbError & getNdbError() const; + + /** @} *******************************************************************/ + + /** + * @name Retrieving references to Tables and Indexes + * @{ + */ + + /** + * Get table with given name, NULL if undefined + * @param name Name of table to get + * @return table if successful otherwise NULL. + */ + const Table * getTable(const char * name) const; + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + /** + * Given main table, get blob table. + */ + const Table * getBlobTable(const Table *, const char * col_name); + const Table * getBlobTable(const Table *, Uint32 col_no); + + /* + * Save a table definition in dictionary cache + * @param table Object to put into cache + */ + void putTable(const Table * table); +#endif + + /** + * Get index with given name, NULL if undefined + * @param indexName Name of index to get. + * @param tableName Name of table that index belongs to. + * @return index if successful, otherwise 0. + */ + const Index * getIndex(const char * indexName, + const char * tableName) const; + + /** + * Fetch list of indexes of given table. + * @param list Reference to list where to store the listed indexes + * @param tableName Name of table that index belongs to. + * @return 0 if successful, otherwise -1 + */ + int listIndexes(List & list, const char * tableName); + int listIndexes(List & list, const char * tableName) const; + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + /** + * Fetch list of indexes of given table. + * @param list Reference to list where to store the listed indexes + * @param table Reference to table that index belongs to. + * @return 0 if successful, otherwise -1 + */ + int listIndexes(List & list, const Table &table) const; +#endif + + /** @} *******************************************************************/ + /** + * @name Events + * @{ + */ + + /** + * Create event given defined Event instance + * @param event Event to create + * @return 0 if successful otherwise -1. + */ + int createEvent(const Event &event); + + /** + * Drop event with given name + * @param eventName Name of event to drop. + * @return 0 if successful otherwise -1. + */ + int dropEvent(const char * eventName); + + /** + * Get event with given name. + * @param eventName Name of event to get. + * @return an Event if successful, otherwise NULL. + */ + const Event * getEvent(const char * eventName); + + /** @} *******************************************************************/ + + /** + * @name Table creation + * @{ + * + * These methods should normally not be used in an application as + * the result will not be visible from the MySQL Server + */ + + /** + * Create defined table given defined Table instance + * @param table Table to create + * @return 0 if successful otherwise -1. + */ + int createTable(const Table &table); + + /** + * Drop table given retrieved Table instance + * @param table Table to drop + * @return 0 if successful otherwise -1. + */ + int dropTable(Table & table); + + /** + * Drop table given table name + * @param name Name of table to drop + * @return 0 if successful otherwise -1. + */ + int dropTable(const char * name); + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + /** + * Alter defined table given defined Table instance + * @param table Table to alter + * @return -2 (incompatible version) <br> + * -1 general error <br> + * 0 success + */ + int alterTable(const Table &table); + + /** + * Invalidate cached table object + * @param name Name of table to invalidate + */ + void invalidateTable(const char * name); +#endif + + /** + * Remove table from local cache + */ + void removeCachedTable(const char * table); + /** + * Remove index from local cache + */ + void removeCachedIndex(const char * index, const char * table); + + + /** @} *******************************************************************/ + /** + * @name Index creation + * @{ + * + * These methods should normally not be used in an application as + * the result will not be visible from the MySQL Server + * + */ + + /** + * Create index given defined Index instance + * @param index Index to create + * @return 0 if successful otherwise -1. + */ + int createIndex(const Index &index); + int createIndex(const Index &index, const Table &table); + + /** + * Drop index with given name + * @param indexName Name of index to drop. + * @param tableName Name of table that index belongs to. + * @return 0 if successful otherwise -1. + */ + int dropIndex(const char * indexName, + const char * tableName); + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + void removeCachedTable(const Table *table); + void removeCachedIndex(const Index *index); + void invalidateTable(const Table *table); + /** + * Invalidate cached index object + */ + void invalidateIndex(const char * indexName, + const char * tableName); + void invalidateIndex(const Index *index); + /** + * Force gcp and wait for gcp complete + */ + int forceGCPWait(); +#endif + + /** @} *******************************************************************/ + + /** @} *******************************************************************/ + /** + * @name Disk data objects + * @{ + */ + + int createLogfileGroup(const LogfileGroup &, ObjectId* = 0); + int dropLogfileGroup(const LogfileGroup&); + LogfileGroup getLogfileGroup(const char * name); + + int createTablespace(const Tablespace &, ObjectId* = 0); + int dropTablespace(const Tablespace&); + Tablespace getTablespace(const char * name); + Tablespace getTablespace(Uint32 tablespaceId); + + int createDatafile(const Datafile &, bool overwrite_existing = false, ObjectId* = 0); + int dropDatafile(const Datafile&); + Datafile getDatafile(Uint32 node, const char * path); + + int createUndofile(const Undofile &, bool overwrite_existing = false, ObjectId * = 0); + int dropUndofile(const Undofile&); + Undofile getUndofile(Uint32 node, const char * path); + + /** @} *******************************************************************/ + + protected: + Dictionary(Ndb & ndb); + ~Dictionary(); + + private: +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + friend class NdbDictionaryImpl; + friend class UtilTransactions; + friend class NdbBlob; +#endif + class NdbDictionaryImpl & m_impl; + Dictionary(NdbDictionaryImpl&); + const Table * getIndexTable(const char * indexName, + const char * tableName) const; + public: +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + const Table * getTable(const char * name, void **data) const; + void set_local_table_data_size(unsigned sz); + + const Index * getIndexGlobal(const char * indexName, + const Table &ndbtab) const; + const Table * getTableGlobal(const char * tableName) const; + int alterTableGlobal(const Table &f, const Table &t); + int dropTableGlobal(const Table &ndbtab); + int dropIndexGlobal(const Index &index); + int removeIndexGlobal(const Index &ndbidx, int invalidate) const; + int removeTableGlobal(const Table &ndbtab, int invalidate) const; +#endif + }; +}; + +class NdbOut& operator <<(class NdbOut& out, const NdbDictionary::Column& col); + +#endif diff --git a/storage/ndb/include/ndbapi/NdbError.hpp b/storage/ndb/include/ndbapi/NdbError.hpp new file mode 100644 index 00000000000..83f24b36313 --- /dev/null +++ b/storage/ndb/include/ndbapi/NdbError.hpp @@ -0,0 +1,250 @@ +/* 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 */ + +#ifndef NDB_ERROR_HPP +#define NDB_ERROR_HPP + +#include <ndberror.h> + +/** + * @struct NdbError + * @brief Contains error information + * + * A NdbError consists of five parts: + * -# Error status : Application impact + * -# Error classification : Logical error group + * -# Error code : Internal error code + * -# Error message : Context independent description of error + * -# Error details : Context dependent information + * (not always available) + * + * <em>Error status</em> is usually used for programming against errors. + * If more detailed error control is needed, it is possible to + * use the <em>error classification</em>. + * + * It is not recommended to write application programs dependent on + * specific <em>error codes</em>. + * + * The <em>error messages</em> and <em>error details</em> may + * change without notice. + * + * For example of use, see @ref ndbapi_retries.cpp. + */ +struct NdbError { + /** + * Status categorizes error codes into status values reflecting + * what the application should do when encountering errors + */ + enum Status { + /** + * The error code indicate success<br> + * (Includes classification: NdbError::NoError) + */ + Success = ndberror_st_success, + + /** + * The error code indicates a temporary error. + * The application should typically retry.<br> + * (Includes classifications: NdbError::InsufficientSpace, + * NdbError::TemporaryResourceError, NdbError::NodeRecoveryError, + * NdbError::OverloadError, NdbError::NodeShutdown + * and NdbError::TimeoutExpired.) + */ + TemporaryError = ndberror_st_temporary, + + /** + * The error code indicates a permanent error.<br> + * (Includes classificatons: NdbError::PermanentError, + * NdbError::ApplicationError, NdbError::NoDataFound, + * NdbError::ConstraintViolation, NdbError::SchemaError, + * NdbError::UserDefinedError, NdbError::InternalError, and, + * NdbError::FunctionNotImplemented.) + */ + PermanentError = ndberror_st_permanent, + + /** + * The result/status is unknown.<br> + * (Includes classifications: NdbError::UnknownResultError, and + * NdbError::UnknownErrorCode.) + */ + UnknownResult = ndberror_st_unknown + }; + + /** + * Type of error + */ + enum Classification { + /** + * Success. No error occurred. + */ + NoError = ndberror_cl_none, + + /** + * Error in application program. + */ + ApplicationError = ndberror_cl_application, + + /** + * Read operation failed due to missing record. + */ + NoDataFound = ndberror_cl_no_data_found, + + /** + * E.g. inserting a tuple with a primary key already existing + * in the table. + */ + ConstraintViolation = ndberror_cl_constraint_violation, + + /** + * Error in creating table or usage of table. + */ + SchemaError = ndberror_cl_schema_error, + + /** + * Error occurred in interpreted program. + */ + UserDefinedError = ndberror_cl_user_defined, + + /** + * E.g. insufficient memory for data or indexes. + */ + InsufficientSpace = ndberror_cl_insufficient_space, + + /** + * E.g. too many active transactions. + */ + TemporaryResourceError = ndberror_cl_temporary_resource, + + /** + * Temporary failures which are probably inflicted by a node + * recovery in progress. Examples: information sent between + * application and NDB lost, distribution change. + */ + NodeRecoveryError = ndberror_cl_node_recovery, + + /** + * E.g. out of log file space. + */ + OverloadError = ndberror_cl_overload, + + /** + * Timeouts, often inflicted by deadlocks in NDB. + */ + TimeoutExpired = ndberror_cl_timeout_expired, + + /** + * Is is unknown whether the transaction was committed or not. + */ + UnknownResultError = ndberror_cl_unknown_result, + + /** + * A serious error in NDB has occurred. + */ + InternalError = ndberror_cl_internal_error, + + /** + * A function used is not yet implemented. + */ + FunctionNotImplemented = ndberror_cl_function_not_implemented, + + /** + * Error handler could not determine correct error code. + */ + UnknownErrorCode = ndberror_cl_unknown_error_code, + + /** + * Node shutdown + */ + NodeShutdown = ndberror_cl_node_shutdown, + + /** + * Schema object already exists + */ + SchemaObjectExists = ndberror_cl_schema_object_already_exists, + + /** + * Request sent to non master + */ + InternalTemporary = ndberror_cl_internal_temporary + }; + + /** + * Error status. + */ + Status status; + + /** + * Error type + */ + Classification classification; + + /** + * Error code + */ + int code; + + /** + * Mysql error code + */ + int mysql_code; + + /** + * Error message + */ + const char * message; + + /** + * The detailed description. This is extra information regarding the + * error which is not included in the error message. + * + * @note Is NULL when no details specified + */ + char * details; + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + NdbError(){ + status = UnknownResult; + classification = NoError; + code = 0; + mysql_code = 0; + message = 0; + details = 0; + } + NdbError(const ndberror_struct & ndberror){ + status = (NdbError::Status) ndberror.status; + classification = (NdbError::Classification) ndberror.classification; + code = ndberror.code; + mysql_code = ndberror.mysql_code; + message = ndberror.message; + details = ndberror.details; + } + operator ndberror_struct() const { + ndberror_struct ndberror; + ndberror.status = (ndberror_status_enum) status; + ndberror.classification = (ndberror_classification_enum) classification; + ndberror.code = code; + ndberror.mysql_code = mysql_code; + ndberror.message = message; + ndberror.details = details; + return ndberror; + } +#endif +}; + +class NdbOut& operator <<(class NdbOut&, const NdbError &); +class NdbOut& operator <<(class NdbOut&, const NdbError::Status&); +class NdbOut& operator <<(class NdbOut&, const NdbError::Classification&); +#endif diff --git a/storage/ndb/include/ndbapi/NdbEventOperation.hpp b/storage/ndb/include/ndbapi/NdbEventOperation.hpp new file mode 100644 index 00000000000..25d7b8c6644 --- /dev/null +++ b/storage/ndb/include/ndbapi/NdbEventOperation.hpp @@ -0,0 +1,261 @@ +/* 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 */ + +#ifndef NdbEventOperation_H +#define NdbEventOperation_H + +class NdbGlobalEventBuffer; +class NdbEventOperationImpl; + +/** + * @class NdbEventOperation + * @brief Class of operations for getting change events from database. + * + * Brief description on how to work with events: + * + * - An event, represented by an NdbDictionary::Event, i created in the + * Database through + * NdbDictionary::Dictionary::createEvent() (note that this can be done + * by any application or thread and not necessarily by the "listener") + * - To listen to events, an NdbEventOperation object is instantiated by + * Ndb::createEventOperation() + * - execute() starts the event flow. Use Ndb::pollEvents() to wait + * for an event to occur. Use Ndb::nextEvent() to iterate + * through the events that have occured. + * - The instance is removed by Ndb::dropEventOperation() + * + * For more info see: + * @ref ndbapi_event.cpp + * + * Known limitations: + * + * - Maximum number of active NdbEventOperations are now set at compile time. + * Today 100. This will become a configuration parameter later. + * - Maximum number of NdbEventOperations tied to same event are maximum 16 + * per process. + * + * Known issues: + * + * - When several NdbEventOperation's are tied to the same event in the same + * process they will share the circular buffer. The BufferLength will then + * be the same for all and decided by the first NdbEventOperation + * instantiation. Just make sure to instantiate the "largest" one first. + * - Today all events INSERT/DELETE/UPDATE and all changed attributes are + * sent to the API, even if only specific attributes have been specified. + * These are however hidden from the user and only relevant data is shown + * after Ndb::nextEvent(). + * - "False" exits from Ndb::pollEvents() may occur and thus + * the subsequent Ndb::nextEvent() will return NULL, + * since there was no available data. Just do Ndb::pollEvents() again. + * - Event code does not check table schema version. Make sure to drop events + * after table is dropped. Will be fixed in later + * versions. + * - If a node failure has occured not all events will be recieved + * anymore. Drop NdbEventOperation and Create again after nodes are up + * again. Will be fixed in later versions. + * + * Test status: + * + * - Tests have been run on 1-node and 2-node systems + * + * Useful API programs: + * + * - ndb_select_all -d sys 'NDB$EVENTS_0' + * shows contents in the system table containing created events. + * + * @note this is an inteface to viewing events that is subject to change + */ +class NdbEventOperation { +public: + /** + * State of the NdbEventOperation object + */ + enum State { + EO_CREATED, ///< Created but execute() not called + EO_EXECUTING, ///< execute() called + EO_DROPPED, ///< Waiting to be deleted, Object unusable. + EO_ERROR ///< An error has occurred. Object unusable. + }; + /** + * Retrieve current state of the NdbEventOperation object + */ + State getState(); + /** + * See NdbDictionary::Event. Default is false. + */ + void mergeEvents(bool flag); + + /** + * Activates the NdbEventOperation to start receiving events. The + * changed attribute values may be retrieved after Ndb::nextEvent() + * has returned not NULL. The getValue() methods must be called + * prior to execute(). + * + * @return 0 if successful otherwise -1. + */ + int execute(); + + /** + * Defines a retrieval operation of an attribute value. + * The NDB API allocate memory for the NdbRecAttr object that + * will hold the returned attribute value. + * + * @note Note that it is the applications responsibility + * to allocate enough memory for aValue (if non-NULL). + * The buffer aValue supplied by the application must be + * aligned appropriately. The buffer is used directly + * (avoiding a copy penalty) only if it is aligned on a + * 4-byte boundary and the attribute size in bytes + * (i.e. NdbRecAttr::attrSize() times NdbRecAttr::arraySize() is + * a multiple of 4). + * + * @note There are two versions, getValue() and + * getPreValue() for retrieving the current and + * previous value repectively. + * + * @note This method does not fetch the attribute value from + * the database! The NdbRecAttr object returned by this method + * is <em>not</em> readable/printable before the + * execute() has been made and + * Ndb::nextEvent() has returned not NULL. + * If a specific attribute has not changed the corresponding + * NdbRecAttr will be in state UNDEFINED. This is checked by + * NdbRecAttr::isNULL() which then returns -1. + * + * @param anAttrName Attribute name + * @param aValue If this is non-NULL, then the attribute value + * will be returned in this parameter.<br> + * If NULL, then the attribute value will only + * be stored in the returned NdbRecAttr object. + * @return An NdbRecAttr object to hold the value of + * the attribute, or a NULL pointer + * (indicating error). + */ + NdbRecAttr *getValue(const char *anAttrName, char *aValue = 0); + /** + * See getValue(). + */ + NdbRecAttr *getPreValue(const char *anAttrName, char *aValue = 0); + + /** + * These methods replace getValue/getPreValue for blobs. Each + * method creates a blob handle NdbBlob. The handle supports only + * read operations. See NdbBlob. + */ + NdbBlob* getBlobHandle(const char *anAttrName); + NdbBlob* getPreBlobHandle(const char *anAttrName); + + int isOverrun() const; + + /** + * In the current implementation a nodefailiure may cause loss of events, + * in which case isConsistent() will return false + */ + bool isConsistent() const; + + /** + * Query for occured event type. + * + * @note Only valid after Ndb::nextEvent() has been called and + * returned a not NULL value + * + * @return type of event + */ + NdbDictionary::Event::TableEvent getEventType() const; + + /** + * Check if table name has changed, for event TE_ALTER + */ + const bool tableNameChanged() const; + + /** + * Check if table frm has changed, for event TE_ALTER + */ + const bool tableFrmChanged() const; + + /** + * Check if table fragmentation has changed, for event TE_ALTER + */ + const bool tableFragmentationChanged() const; + + /** + * Check if table range partition list name has changed, for event TE_ALTER + */ + const bool tableRangeListChanged() const; + + /** + * Retrieve the GCI of the latest retrieved event + * + * @return GCI number + */ + Uint64 getGCI() const; + + /** + * Retrieve the complete GCI in the cluster (not necessarily + * associated with an event) + * + * @return GCI number + */ + Uint64 getLatestGCI() const; + + /** + * Get the latest error + * + * @return Error object. + */ + const struct NdbError & getNdbError() const; + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + /** these are subject to change at any time */ + const NdbDictionary::Table* getTable() const; + const NdbDictionary::Event *getEvent() const; + const NdbRecAttr *getFirstPkAttr() const; + const NdbRecAttr *getFirstPkPreAttr() const; + const NdbRecAttr *getFirstDataAttr() const; + const NdbRecAttr *getFirstDataPreAttr() const; + +// bool validateTable(NdbDictionary::Table &table) const; + + void setCustomData(void * data); + void * getCustomData() const; + + void clearError(); + int hasError() const; + + int getReqNodeId() const; + int getNdbdNodeId() const; +#endif + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + /* + * + */ + void print(); +#endif + +private: +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + friend class NdbEventOperationImpl; + friend class NdbEventBuffer; +#endif + NdbEventOperation(Ndb *theNdb, const char* eventName); + ~NdbEventOperation(); + class NdbEventOperationImpl &m_impl; + NdbEventOperation(NdbEventOperationImpl& impl); +}; + +typedef void (* NdbEventCallback)(NdbEventOperation*, Ndb*, void*); +#endif diff --git a/storage/ndb/include/ndbapi/NdbIndexOperation.hpp b/storage/ndb/include/ndbapi/NdbIndexOperation.hpp new file mode 100644 index 00000000000..d16cd071f77 --- /dev/null +++ b/storage/ndb/include/ndbapi/NdbIndexOperation.hpp @@ -0,0 +1,192 @@ +/* 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 */ + +#ifndef NdbIndexOperation_H +#define NdbIndexOperation_H + +#include "NdbOperation.hpp" + +class Index; +class NdbResultSet; + +/** + * @class NdbIndexOperation + * @brief Class of index operations for use in transactions + */ +class NdbIndexOperation : public NdbOperation +{ +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + friend class Ndb; + friend class NdbTransaction; +#endif + +public: + /** + * @name Define Standard Operation + * @{ + */ + + /** insert is not allowed */ + int insertTuple(); + + /** + * Define the NdbIndexOperation to be a standard operation of type readTuple. + * When calling NdbTransaction::execute, this operation + * reads a tuple. + * + * @return 0 if successful otherwise -1. + */ + int readTuple(LockMode); + +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + /** + * Define the NdbIndexOperation to be a standard operation of type readTuple. + * When calling NdbTransaction::execute, this operation + * reads a tuple. + * + * @return 0 if successful otherwise -1. + */ + int readTuple(); + + /** + * Define the NdbIndexOperation to be a standard operation of type + * readTupleExclusive. + * When calling NdbTransaction::execute, this operation + * read a tuple using an exclusive lock. + * + * @return 0 if successful otherwise -1. + */ + int readTupleExclusive(); + + /** + * Define the NdbIndexOperation to be a standard operation of type simpleRead. + * When calling NdbTransaction::execute, this operation + * reads an existing tuple (using shared read lock), + * but releases lock immediately after read. + * + * @note Using this operation twice in the same transaction + * may produce different results (e.g. if there is another + * transaction which updates the value between the + * simple reads). + * + * Note that simpleRead can read the value from any database node while + * standard read always read the value on the database node which is + * primary for the record. + * + * @return 0 if successful otherwise -1. + */ + int simpleRead(); + + /** + * Define the NdbOperation to be a standard operation of type committedRead. + * When calling NdbTransaction::execute, this operation + * read latest committed value of the record. + * + * This means that if another transaction is updating the + * record, then the current transaction will not wait. + * It will instead use the latest committed value of the + * record. + * + * @return 0 if successful otherwise -1. + */ + int dirtyRead(); + + int committedRead(); +#endif + + /** + * Define the NdbIndexOperation to be a standard operation of type + * updateTuple. + * + * When calling NdbTransaction::execute, this operation + * updates a tuple in the table. + * + * @return 0 if successful otherwise -1. + */ + int updateTuple(); + + /** + * Define the NdbIndexOperation to be a standard operation of type + * deleteTuple. + * + * When calling NdbTransaction::execute, this operation + * deletes a tuple. + * + * @return 0 if successful otherwise -1. + */ + int deleteTuple(); + + /** + * Get index object for this operation + */ + const NdbDictionary::Index * getIndex() const; + +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + /** + * Define the NdbIndexOperation to be a standard operation of type + * dirtyUpdate. + * + * When calling NdbTransaction::execute, this operation + * updates without two-phase commit. + * + * @return 0 if successful otherwise -1. + */ + int dirtyUpdate(); +#endif + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + /** @} *********************************************************************/ + /** + * @name Define Interpreted Program Operation + * @{ + */ + + /** + * Update a tuple using an interpreted program. + * + * @return 0 if successful otherwise -1. + */ + int interpretedUpdateTuple(); + + /** + * Delete a tuple using an interpreted program. + * + * @return 0 if successful otherwise -1. + */ + int interpretedDeleteTuple(); +#endif + + /** @} *********************************************************************/ + +private: + NdbIndexOperation(Ndb* aNdb); + ~NdbIndexOperation(); + + int receiveTCINDXREF(NdbApiSignal* aSignal); + + // Overloaded methods from NdbCursorOperation + int indxInit(const class NdbIndexImpl* anIndex, + const class NdbTableImpl* aTable, + NdbTransaction*); + + int prepareSend(Uint32 TC_ConnectPtr, Uint64 TransactionId); + + // Private attributes + const NdbIndexImpl* m_theIndex; + friend struct Ndb_free_list_t<NdbIndexOperation>; +}; + +#endif diff --git a/storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp b/storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp new file mode 100644 index 00000000000..eeafe98b46e --- /dev/null +++ b/storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp @@ -0,0 +1,204 @@ +/* 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 */ + +#ifndef NdbIndexScanOperation_H +#define NdbIndexScanOperation_H + +#include <NdbScanOperation.hpp> + +/** + * @class NdbIndexScanOperation + * @brief Class of scan operations for use to scan ordered index + */ +class NdbIndexScanOperation : public NdbScanOperation { +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + friend class Ndb; + friend class NdbTransaction; + friend class NdbResultSet; + friend class NdbOperation; + friend class NdbScanOperation; + friend class NdbIndexStat; +#endif + +public: + /** + * readTuples using ordered index + * + * @param lock_mode Lock mode + * @param scan_flags see @ref ScanFlag + * @param parallel No of fragments to scan in parallel (0=max) + */ + virtual int readTuples(LockMode lock_mode = LM_Read, + Uint32 scan_flags = 0, + Uint32 parallel = 0, + Uint32 batch = 0); + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + /** + * readTuples using ordered index + * + * @param lock_mode Lock mode + * @param batch No of rows to fetch from each fragment at a time + * @param parallel No of fragments to scan in parallel + * @param order_by Order result set in index order + * @param order_desc Order descending, ignored unless order_by + * @param read_range_no Enable reading of range no using @ref get_range_no + * @returns 0 for success and -1 for failure + * @see NdbScanOperation::readTuples + */ + inline int readTuples(LockMode lock_mode, + Uint32 batch, + Uint32 parallel, + bool order_by, + bool order_desc = false, + bool read_range_no = false, + bool keyinfo = false) { + Uint32 scan_flags = + (SF_OrderBy & -(Int32)order_by) | + (SF_Descending & -(Int32)order_desc) | + (SF_ReadRangeNo & -(Int32)read_range_no) | + (SF_KeyInfo & -(Int32)keyinfo); + + return readTuples(lock_mode, scan_flags, parallel, batch); + } +#endif + + /** + * Type of ordered index key bound. The values (0-4) will not change + * and can be used explicitly (e.g. they could be computed). + */ + enum BoundType { + BoundLE = 0, ///< lower bound + BoundLT = 1, ///< lower bound, strict + BoundGE = 2, ///< upper bound + BoundGT = 3, ///< upper bound, strict + BoundEQ = 4 ///< equality + }; + + /** + * Define bound on index key in range scan. + * + * Each index key can have lower and/or upper bound. Setting the key + * equal to a value defines both upper and lower bounds. The bounds + * can be defined in any order. Conflicting definitions is an error. + * + * For equality, it is better to use BoundEQ instead of the equivalent + * pair of BoundLE and BoundGE. This is especially true when table + * partition key is an initial part of the index key. + * + * The sets of lower and upper bounds must be on initial sequences of + * index keys. All but possibly the last bound must be non-strict. + * So "a >= 2 and b > 3" is ok but "a > 2 and b >= 3" is not. + * + * The scan may currently return tuples for which the bounds are not + * satisfied. For example, "a <= 2 and b <= 3" scans the index up to + * (a=2, b=3) but also returns any (a=1, b=4). + * + * NULL is treated like a normal value which is less than any not-NULL + * value and equal to another NULL value. To compare against NULL use + * setBound with null pointer (0). + * + * An index stores also all-NULL keys. Doing index scan with empty + * bound set returns all table tuples. + * + * @param attr Attribute name, alternatively: + * @param type Type of bound + * @param value Pointer to bound value, 0 for NULL + * @return 0 if successful otherwise -1 + * + * @note See comment under equal() about data format and length. + */ +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + int setBound(const char* attr, int type, const void* value, Uint32 len); +#endif + int setBound(const char* attr, int type, const void* value); + + /** + * Define bound on index key in range scan using index column id. + * See the other setBound() method for details. + */ +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + int setBound(Uint32 anAttrId, int type, const void* aValue, Uint32 len); +#endif + int setBound(Uint32 anAttrId, int type, const void* aValue); + + /** + * Reset bounds and put operation in list that will be + * sent on next execute + */ + int reset_bounds(bool forceSend = false); + + /** + * Marks end of a bound, + * used when batching index reads (multiple ranges) + */ + int end_of_bound(Uint32 range_no); + + /** + * Return range no for current row + */ + int get_range_no(); + + /** + * Is current scan sorted + */ + bool getSorted() const { return m_ordered; } + + /** + * Is current scan sorted descending + */ + bool getDescending() const { return m_descending; } + +private: + NdbIndexScanOperation(Ndb* aNdb); + virtual ~NdbIndexScanOperation(); + + int setBound(const NdbColumnImpl*, int type, const void* aValue); + int insertBOUNDS(Uint32 * data, Uint32 sz); + Uint32 getKeyFromSCANTABREQ(Uint32* data, Uint32 size); + + virtual int equal_impl(const NdbColumnImpl*, const char*); + virtual NdbRecAttr* getValue_impl(const NdbColumnImpl*, char*); + + void fix_get_values(); + int next_result_ordered(bool fetchAllowed, bool forceSend = false); + int send_next_scan_ordered(Uint32 idx); + int compare(Uint32 key, Uint32 cols, const NdbReceiver*, const NdbReceiver*); + + Uint32 m_sort_columns; + Uint32 m_this_bound_start; + Uint32 * m_first_bound_word; + + friend struct Ndb_free_list_t<NdbIndexScanOperation>; +}; + +inline +int +NdbIndexScanOperation::setBound(const char* attr, int type, const void* value, + Uint32 len) +{ + return setBound(attr, type, value); +} + +inline +int +NdbIndexScanOperation::setBound(Uint32 anAttrId, int type, const void* value, + Uint32 len) +{ + return setBound(anAttrId, type, value); +} + +#endif diff --git a/storage/ndb/include/ndbapi/NdbIndexStat.hpp b/storage/ndb/include/ndbapi/NdbIndexStat.hpp new file mode 100644 index 00000000000..ddd27ed24d4 --- /dev/null +++ b/storage/ndb/include/ndbapi/NdbIndexStat.hpp @@ -0,0 +1,147 @@ +/* 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 */ + +#ifndef NdbIndexStat_H +#define NdbIndexStat_H + +#include <ndb_global.h> +#include <NdbDictionary.hpp> +#include <NdbError.hpp> +class NdbIndexImpl; +class NdbIndexScanOperation; + +/* + * Statistics for an ordered index. + */ +class NdbIndexStat { +public: + NdbIndexStat(const NdbDictionary::Index* index); + ~NdbIndexStat(); + /* + * Allocate memory for cache. Argument is minimum number of stat + * entries and applies to lower and upper bounds separately. More + * entries may fit (keys have variable size). If not used, db is + * contacted always. + */ + int alloc_cache(Uint32 entries); + /* + * Flags for records_in_range. + */ + enum { + RR_UseDb = 1, // contact db + RR_NoUpdate = 2 // but do not update cache + }; + /* + * Estimate how many index records need to be scanned. The scan + * operation must be prepared with lock mode LM_CommittedRead and must + * have the desired bounds set. The routine may use local cache or + * may contact db by executing the operation. + * + * If returned count is zero then db was contacted and the count is + * exact. Otherwise the count is approximate. If cache is used then + * caller must provide estimated number of table rows. It will be + * multiplied by a percentage obtained from the cache (result zero is + * returned as 1). + */ + int records_in_range(const NdbDictionary::Index* index, + NdbIndexScanOperation* op, + Uint64 table_rows, + Uint64* count, + int flags); + /* + * Get latest error. + */ + const NdbError& getNdbError() const; + +private: + /* + * There are 2 areas: start keys and end keys. An area has pointers + * at beginning and entries at end. Pointers are sorted by key. + * + * A pointer contains entry offset and also entry timestamp. An entry + * contains the key and percentage of rows _not_ satisfying the bound + * i.e. less than start key or greater than end key. + * + * A key is an array of index key bounds. Each has type (0-4) in + * first word followed by data with AttributeHeader. + * + * Stat update comes as pair of start and end key and associated + * percentages. Stat query takes best match of start and end key from + * each area separately. Rows in range percentage is then computed by + * excluding the two i.e. as 100 - (start key pct + end key pct). + * + * TODO use more compact key format + */ + struct Pointer; + friend struct Pointer; + struct Entry; + friend struct Entry; + struct Area; + friend struct Area; + struct Pointer { + Uint16 m_pos; + Uint16 m_seq; + }; + struct Entry { + float m_pct; + Uint32 m_keylen; + }; + STATIC_CONST( EntrySize = sizeof(Entry) >> 2 ); + STATIC_CONST( PointerSize = sizeof(Pointer) >> 2 ); + struct Area { + Uint32* m_data; + Uint32 m_offset; + Uint32 m_free; + Uint16 m_entries; + Uint8 m_idir; + Uint8 pad1; + Area() {} + Pointer& get_pointer(unsigned i) const { + return *(Pointer*)&m_data[i]; + } + Entry& get_entry(unsigned i) const { + return *(Entry*)&m_data[get_pointer(i).m_pos]; + } + Uint32 get_pos(const Entry& e) const { + return (const Uint32*)&e - m_data; + } + unsigned get_firstpos() const { + return PointerSize * m_entries + m_free; + } + }; + const NdbIndexImpl& m_index; + Uint32 m_areasize; + Uint16 m_seq; + Area m_area[2]; + Uint32* m_cache; + NdbError m_error; +#ifdef VM_TRACE + void stat_verify(); +#endif + int stat_cmpkey(const Area& a, const Uint32* key1, Uint32 keylen1, + const Uint32* key2, Uint32 keylen2); + int stat_search(const Area& a, const Uint32* key, Uint32 keylen, + Uint32* idx, bool* match); + int stat_oldest(const Area& a); + int stat_delete(Area& a, Uint32 k); + int stat_update(const Uint32* key1, Uint32 keylen1, + const Uint32* key2, Uint32 keylen2, const float pct[2]); + int stat_select(const Uint32* key1, Uint32 keylen1, + const Uint32* key2, Uint32 keylen2, float pct[2]); + void set_error(int code); +}; + +#endif diff --git a/storage/ndb/include/ndbapi/NdbOperation.hpp b/storage/ndb/include/ndbapi/NdbOperation.hpp new file mode 100644 index 00000000000..7f026e29578 --- /dev/null +++ b/storage/ndb/include/ndbapi/NdbOperation.hpp @@ -0,0 +1,1311 @@ +/* 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 */ + +#ifndef NdbOperation_H +#define NdbOperation_H + +#include <ndb_types.h> +#include "ndbapi_limits.h" +#include "NdbError.hpp" +#include "NdbReceiver.hpp" +#include "NdbDictionary.hpp" +#include "Ndb.hpp" + +class Ndb; +class NdbApiSignal; +class NdbRecAttr; +class NdbOperation; +class NdbTransaction; +class NdbColumnImpl; +class NdbBlob; + +/** + * @class NdbOperation + * @brief Class of operations for use in transactions. + */ +class NdbOperation +{ +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + friend class Ndb; + friend class NdbTransaction; + friend class NdbScanOperation; + friend class NdbScanReceiver; + friend class NdbScanFilter; + friend class NdbScanFilterImpl; + friend class NdbReceiver; + friend class NdbBlob; +#endif + +public: + /** + * @name Define Standard Operation Type + * @{ + */ + + /** + * Different access types (supported by sub-classes of NdbOperation) + */ + + enum Type { + PrimaryKeyAccess ///< Read, insert, update, or delete using pk +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + = 0 // NdbOperation +#endif + ,UniqueIndexAccess ///< Read, update, or delete using unique index +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + = 1 // NdbIndexOperation +#endif + ,TableScan ///< Full table scan +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + = 2 // NdbScanOperation +#endif + ,OrderedIndexScan ///< Ordered index scan +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + = 3 // NdbIndexScanOperation +#endif + }; + + /** + * Lock when performing read + */ + + enum LockMode { + LM_Read ///< Read with shared lock +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + = 0 +#endif + ,LM_Exclusive ///< Read with exclusive lock +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + = 1 +#endif + ,LM_CommittedRead ///< Ignore locks, read last committed value +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + = 2, + LM_Dirty = 2 +#endif + }; + + /** + * Define the NdbOperation to be a standard operation of type insertTuple. + * When calling NdbTransaction::execute, this operation + * adds a new tuple to the table. + * + * @return 0 if successful otherwise -1. + */ + virtual int insertTuple(); + + /** + * Define the NdbOperation to be a standard operation of type updateTuple. + * When calling NdbTransaction::execute, this operation + * updates a tuple in the table. + * + * @return 0 if successful otherwise -1. + */ + virtual int updateTuple(); + + /** + * Define the NdbOperation to be a standard operation of type writeTuple. + * When calling NdbTransaction::execute, this operation + * writes a tuple to the table. + * If the tuple exists, it updates it, otherwise an insert takes place. + * + * @return 0 if successful otherwise -1. + */ + virtual int writeTuple(); + + /** + * Define the NdbOperation to be a standard operation of type deleteTuple. + * When calling NdbTransaction::execute, this operation + * delete a tuple. + * + * @return 0 if successful otherwise -1. + */ + virtual int deleteTuple(); + + /** + * Define the NdbOperation to be a standard operation of type readTuple. + * When calling NdbTransaction::execute, this operation + * reads a tuple. + * + * @return 0 if successful otherwise -1. + */ + virtual int readTuple(LockMode); + +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + /** + * Define the NdbOperation to be a standard operation of type readTuple. + * When calling NdbTransaction::execute, this operation + * reads a tuple. + * + * @return 0 if successful otherwise -1. + */ + virtual int readTuple(); + + /** + * Define the NdbOperation to be a standard operation of type + * readTupleExclusive. + * When calling NdbTransaction::execute, this operation + * read a tuple using an exclusive lock. + * + * @return 0 if successful otherwise -1. + */ + virtual int readTupleExclusive(); + + /** + * Define the NdbOperation to be a standard operation of type + * simpleRead. + * When calling NdbTransaction::execute, this operation + * reads an existing tuple (using shared read lock), + * but releases lock immediately after read. + * + * @note Using this operation twice in the same transaction + * may produce different results (e.g. if there is another + * transaction which updates the value between the + * simple reads). + * + * Note that simpleRead can read the value from any database node while + * standard read always read the value on the database node which is + * primary for the record. + * + * @return 0 if successful otherwise -1. + */ + virtual int simpleRead(); + + /** + * Define the NdbOperation to be a standard operation of type committedRead. + * When calling NdbTransaction::execute, this operation + * read latest committed value of the record. + * + * This means that if another transaction is updating the + * record, then the current transaction will not wait. + * It will instead use the latest committed value of the + * record. + * dirtyRead is a deprecated name for committedRead + * + * @return 0 if successful otherwise -1. + * @depricated + */ + virtual int dirtyRead(); + + /** + * Define the NdbOperation to be a standard operation of type committedRead. + * When calling NdbTransaction::execute, this operation + * read latest committed value of the record. + * + * This means that if another transaction is updating the + * record, then the current transaction will not wait. + * It will instead use the latest committed value of the + * record. + * + * @return 0 if successful otherwise -1. + */ + virtual int committedRead(); + + /** + * Define the NdbOperation to be a standard operation of type dirtyUpdate. + * When calling NdbTransaction::execute, this operation + * updates without two-phase commit. + * + * @return 0 if successful otherwise -1. + */ + virtual int dirtyUpdate(); + + /** + * Define the NdbOperation to be a standard operation of type dirtyWrite. + * When calling NdbTransaction::execute, this operation + * writes without two-phase commit. + * + * @return 0 if successful otherwise -1. + */ + virtual int dirtyWrite(); +#endif + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + /** @} *********************************************************************/ + /** + * @name Define Interpreted Program Operation Type + * @{ + */ + + /** + * Update a tuple using an interpreted program. + * + * @return 0 if successful otherwise -1. + */ + virtual int interpretedUpdateTuple(); + + /** + * Delete a tuple using an interpreted program. + * + * @return 0 if successful otherwise -1. + */ + virtual int interpretedDeleteTuple(); +#endif + + /** @} *********************************************************************/ + + /** + * @name Specify Search Conditions + * @{ + */ + /** + * Define a search condition with equality. + * The condition is true if the attribute has the given value. + * To set search conditions on multiple attributes, + * use several equals (then all of them must be satisfied for the + * tuple to be selected). + * + * @note For insertTuple() it is also allowed to define the + * search key by using setValue(). + * + * @note There are 10 versions of equal() with + * slightly different parameters. + * + * @note If attribute has fixed size, value must include all bytes. + * In particular a Char must be native-blank padded. + * If attribute has variable size, value must start with + * 1 or 2 little-endian length bytes (2 if Long*). + * + * @param anAttrName Attribute name + * @param aValue Attribute value. + * @return -1 if unsuccessful. + */ +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + int equal(const char* anAttrName, const char* aValue, Uint32 len); +#endif + int equal(const char* anAttrName, const char* aValue); + int equal(const char* anAttrName, Int32 aValue); + int equal(const char* anAttrName, Uint32 aValue); + int equal(const char* anAttrName, Int64 aValue); + int equal(const char* anAttrName, Uint64 aValue); +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + int equal(Uint32 anAttrId, const char* aValue, Uint32 len); +#endif + int equal(Uint32 anAttrId, const char* aValue); + int equal(Uint32 anAttrId, Int32 aValue); + int equal(Uint32 anAttrId, Uint32 aValue); + int equal(Uint32 anAttrId, Int64 aValue); + int equal(Uint32 anAttrId, Uint64 aValue); + + /** @} *********************************************************************/ + /** + * @name Specify Attribute Actions for Operations + * @{ + */ + + /** + * Defines a retrieval operation of an attribute value. + * The NDB API allocate memory for the NdbRecAttr object that + * will hold the returned attribute value. + * + * @note Note that it is the applications responsibility + * to allocate enough memory for aValue (if non-NULL). + * The buffer aValue supplied by the application must be + * aligned appropriately. The buffer is used directly + * (avoiding a copy penalty) only if it is aligned on a + * 4-byte boundary and the attribute size in bytes + * (i.e. NdbRecAttr::attrSize times NdbRecAttr::arraySize is + * a multiple of 4). + * + * @note There are two versions of NdbOperation::getValue with + * slightly different parameters. + * + * @note This method does not fetch the attribute value from + * the database! The NdbRecAttr object returned by this method + * is <em>not</em> readable/printable before the + * transaction has been executed with NdbTransaction::execute. + * + * @param anAttrName Attribute name + * @param aValue If this is non-NULL, then the attribute value + * will be returned in this parameter.<br> + * If NULL, then the attribute value will only + * be stored in the returned NdbRecAttr object. + * @return An NdbRecAttr object to hold the value of + * the attribute, or a NULL pointer + * (indicating error). + */ + NdbRecAttr* getValue(const char* anAttrName, char* aValue = 0); + NdbRecAttr* getValue(Uint32 anAttrId, char* aValue = 0); + NdbRecAttr* getValue(const NdbDictionary::Column*, char* val = 0); + + /** + * Define an attribute to set or update in query. + * + * To set a NULL value, use the following construct: + * @code + * setValue("ATTR_NAME", (char*)NULL); + * @endcode + * + * There are a number of NdbOperation::setValue methods that + * take a certain type as input + * (pass by value rather than passing a pointer). + * As the interface is currently implemented it is the responsibility + * of the application programmer to use the correct types. + * + * The NDB API will however check that the application sends + * a correct length to the interface as given in the length parameter. + * The passing of char* as the value can contain any type or + * any type of array. + * If length is not provided or set to zero, + * then the API will assume that the pointer + * is correct and not bother with checking it. + * + * @note For insertTuple() the NDB API will automatically detect that + * it is supposed to use equal() instead. + * + * @note For insertTuple() it is not necessary to use + * setValue() on key attributes before other attributes. + * + * @note There are 14 versions of NdbOperation::setValue with + * slightly different parameters. + * + * @note See note under equal() about value format and length. + * + * @param anAttrName Name (or Id) of attribute. + * @param aValue Attribute value to set. + * @return -1 if unsuccessful. + */ +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + int setValue(const char* anAttrName, const char* aValue, Uint32 len); +#endif + int setValue(const char* anAttrName, const char* aValue); + int setValue(const char* anAttrName, Int32 aValue); + int setValue(const char* anAttrName, Uint32 aValue); + int setValue(const char* anAttrName, Int64 aValue); + int setValue(const char* anAttrName, Uint64 aValue); + int setValue(const char* anAttrName, float aValue); + int setValue(const char* anAttrName, double aValue); + +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + int setValue(Uint32 anAttrId, const char* aValue, Uint32 len); +#endif + int setValue(Uint32 anAttrId, const char* aValue); + int setValue(Uint32 anAttrId, Int32 aValue); + int setValue(Uint32 anAttrId, Uint32 aValue); + int setValue(Uint32 anAttrId, Int64 aValue); + int setValue(Uint32 anAttrId, Uint64 aValue); + int setValue(Uint32 anAttrId, float aValue); + int setValue(Uint32 anAttrId, double aValue); + + /** + * This method replaces getValue/setValue for blobs. It creates + * a blob handle NdbBlob. A second call with same argument returns + * the previously created handle. The handle is linked to the + * operation and is maintained automatically. + * + * See NdbBlob for details. + */ + virtual NdbBlob* getBlobHandle(const char* anAttrName); + virtual NdbBlob* getBlobHandle(Uint32 anAttrId); + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + /** @} *********************************************************************/ + /** + * @name Specify Interpreted Program Instructions + * @{ + */ + + /** + * Interpreted program instruction: Add a value to an attribute. + * + * @note Destroys the contents of registers 6 and 7. + * (The instruction uses these registers for its operation.) + * + * @note There are four versions of NdbOperation::incValue with + * slightly different parameters. + * + * @param anAttrName Attribute name. + * @param aValue Value to add. + * @return -1 if unsuccessful. + */ + int incValue(const char* anAttrName, Uint32 aValue); + int incValue(const char* anAttrName, Uint64 aValue); + int incValue(Uint32 anAttrId, Uint32 aValue); + int incValue(Uint32 anAttrId, Uint64 aValue); + + /** + * Interpreted program instruction: + * Subtract a value from an attribute in an interpreted operation. + * + * @note Destroys the contents of registers 6 and 7. + * (The instruction uses these registers for its operation.) + * + * @note There are four versions of NdbOperation::subValue with + * slightly different parameters. + * + * @param anAttrName Attribute name. + * @param aValue Value to subtract. + * @return -1 if unsuccessful. + */ + int subValue(const char* anAttrName, Uint32 aValue); + int subValue(const char* anAttrName, Uint64 aValue); + int subValue(Uint32 anAttrId, Uint32 aValue); + int subValue(Uint32 anAttrId, Uint64 aValue); + + /** + * Interpreted program instruction: + * Define a jump label in an interpreted operation. + * + * @note The labels are automatically numbered starting with 0. + * The parameter used by NdbOperation::def_label should + * match the automatic numbering to make it easier to + * debug the interpreted program. + * + * @param labelNumber Label number. + * @return -1 if unsuccessful. + */ + int def_label(int labelNumber); + + /** + * Interpreted program instruction: + * Add two registers into a third. + * + * @param RegSource1 First register. + * @param RegSource2 Second register. + * @param RegDest Destination register where the result will be stored. + * @return -1 if unsuccessful. + */ + int add_reg(Uint32 RegSource1, Uint32 RegSource2, Uint32 RegDest); + + /** + * Interpreted program instruction: + * Substract RegSource2 from RegSource1 and put the result in RegDest. + * + * @param RegSource1 First register. + * @param RegSource2 Second register. + * @param RegDest Destination register where the result will be stored. + * @return -1 if unsuccessful. + */ + int sub_reg(Uint32 RegSource1, Uint32 RegSource2, Uint32 RegDest); + + /** + * Interpreted program instruction: + * Load a constant into a register. + * + * @param RegDest Destination register. + * @param Constant Value to load. + * @return -1 if unsuccessful. + */ + int load_const_u32(Uint32 RegDest, Uint32 Constant); + int load_const_u64(Uint32 RegDest, Uint64 Constant); + + /** + * Interpreted program instruction: + * Load NULL value into a register. + * + * @param RegDest Destination register. + * @return -1 if unsuccessful. + */ + int load_const_null(Uint32 RegDest); + + /** + * Interpreted program instruction: + * Read an attribute into a register. + * + * @param anAttrName Attribute name. + * @param RegDest Destination register. + * @return -1 if unsuccessful. + */ + int read_attr(const char* anAttrName, Uint32 RegDest); + + /** + * Interpreted program instruction: + * Write an attribute from a register. + * + * @param anAttrName Attribute name. + * @param RegSource Source register. + * @return -1 if unsuccessful. + */ + int write_attr(const char* anAttrName, Uint32 RegSource); + + /** + * Interpreted program instruction: + * Read an attribute into a register. + * + * @param anAttrId the attribute id. + * @param RegDest the destination register. + * @return -1 if unsuccessful. + */ + int read_attr(Uint32 anAttrId, Uint32 RegDest); + + /** + * Interpreted program instruction: + * Write an attribute from a register. + * + * @param anAttrId the attribute id. + * @param RegSource the source register. + * @return -1 if unsuccessful. + */ + int write_attr(Uint32 anAttrId, Uint32 RegSource); + + /** + * Interpreted program instruction: + * Define a search condition. Last two letters in the function name + * describes the search condition. + * The condition compares RegR with RegL and therefore appears + * to be reversed. + * + * - ge RegR >= RegL + * - gt RegR > RegL + * - le RegR <= RegL + * - lt RegR < RegL + * - eq RegR = RegL + * - ne RegR <> RegL + * + * @param RegLvalue left value. + * @param RegRvalue right value. + * @param Label the label to jump to. + * @return -1 if unsuccessful. + */ + int branch_ge(Uint32 RegLvalue, Uint32 RegRvalue, Uint32 Label); + int branch_gt(Uint32 RegLvalue, Uint32 RegRvalue, Uint32 Label); + int branch_le(Uint32 RegLvalue, Uint32 RegRvalue, Uint32 Label); + int branch_lt(Uint32 RegLvalue, Uint32 RegRvalue, Uint32 Label); + int branch_eq(Uint32 RegLvalue, Uint32 RegRvalue, Uint32 Label); + int branch_ne(Uint32 RegLvalue, Uint32 RegRvalue, Uint32 Label); + + /** + * Interpreted program instruction: + * Jump to Label if RegLvalue is not NULL. + * + * @param RegLvalue the value to check. + * @param Label the label to jump to. + * @return -1 if unsuccessful. + */ + int branch_ne_null(Uint32 RegLvalue, Uint32 Label); + + /** + * Interpreted program instruction: + * Jump to Label if RegLvalue is equal to NULL. + * + * @param RegLvalue Value to check. + * @param Label Label to jump to. + * @return -1 if unsuccessful. + */ + int branch_eq_null(Uint32 RegLvalue, Uint32 Label); + + /** + * Interpreted program instruction: + * Jump to Label. + * + * @param Label Label to jump to. + * @return -1 if unsuccessful. + */ + int branch_label(Uint32 Label); + + /** + * Interpreted program instruction: branch after memcmp + * @param ColId Column to check + * @param Label Label to jump to + * @return -1 if unsuccessful + */ + int branch_col_eq_null(Uint32 ColId, Uint32 Label); + int branch_col_ne_null(Uint32 ColId, Uint32 Label); + + /** + * Interpreted program instruction: branch after memcmp + * @param ColId column to check + * @param val search value + * @param len length of search value + * @param nopad force non-padded comparison for a Char column + * @param Label label to jump to + * @return -1 if unsuccessful + */ + int branch_col_eq(Uint32 ColId, const void * val, Uint32 len, + bool nopad, Uint32 Label); + int branch_col_ne(Uint32 ColId, const void * val, Uint32 len, + bool nopad, Uint32 Label); + int branch_col_lt(Uint32 ColId, const void * val, Uint32 len, + bool nopad, Uint32 Label); + int branch_col_le(Uint32 ColId, const void * val, Uint32 len, + bool nopad, Uint32 Label); + int branch_col_gt(Uint32 ColId, const void * val, Uint32 len, + bool nopad, Uint32 Label); + int branch_col_ge(Uint32 ColId, const void * val, Uint32 len, + bool nopad, Uint32 Label); + /** + * The argument is always plain char, even if the field is varchar + * (changed in 5.0.22). + */ + int branch_col_like(Uint32 ColId, const void *, Uint32 len, + bool nopad, Uint32 Label); + int branch_col_notlike(Uint32 ColId, const void *, Uint32 len, + bool nopad, Uint32 Label); + + /** + * Interpreted program instruction: Exit with Ok + * + * For scanning transactions, + * end interpreted operation and return the row to the application. + * + * For non-scanning transactions, + * exit interpreted program. + * + * @return -1 if unsuccessful. + */ + int interpret_exit_ok(); + + /** + * Interpreted program instruction: Exit with Not Ok + * + * For scanning transactions, + * continue with the next row without returning the current row. + * + * For non-scanning transactions, + * abort the whole transaction. + * + * @note A method also exists without the error parameter. + * + * @param ErrorCode An error code given by the application programmer. + * @return -1 if unsuccessful. + */ + int interpret_exit_nok(Uint32 ErrorCode); + int interpret_exit_nok(); + + + /** + * Interpreted program instruction: + * + * For scanning transactions, + * return this row, but no more from this fragment + * + * For non-scanning transactions, + * abort the whole transaction. + * + * @return -1 if unsuccessful. + */ + int interpret_exit_last_row(); + + /** + * Interpreted program instruction: + * Define a subroutine in an interpreted operation. + * + * @param SubroutineNumber the subroutine number. + * @return -1 if unsuccessful. + */ + int def_subroutine(int SubroutineNumber); + + /** + * Interpreted program instruction: + * Call a subroutine. + * + * @param Subroutine the subroutine to call. + * @return -1 if unsuccessful. + */ + int call_sub(Uint32 Subroutine); + + /** + * Interpreted program instruction: + * End a subroutine. + * + * @return -1 if unsuccessful. + */ + int ret_sub(); +#endif + + /** @} *********************************************************************/ + + /** + * @name Error Handling + * @{ + */ + + /** + * Get the latest error code. + * + * @return error code. + */ + const NdbError & getNdbError() const; + + /** + * Get the method number where the error occured. + * + * @return method number where the error occured. + */ + int getNdbErrorLine(); + + /** + * Get table name of this operation. + */ + const char* getTableName() const; + + /** + * Get table object for this operation + */ + const NdbDictionary::Table * getTable() const; + + /** + * Get the type of access for this operation + */ + const Type getType() const; + + /** @} *********************************************************************/ + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + /** + * Type of operation + */ + enum OperationType { + ReadRequest = 0, ///< Read operation + UpdateRequest = 1, ///< Update Operation + InsertRequest = 2, ///< Insert Operation + DeleteRequest = 3, ///< Delete Operation + WriteRequest = 4, ///< Write Operation + ReadExclusive = 5, ///< Read exclusive + OpenScanRequest, ///< Scan Operation + OpenRangeScanRequest, ///< Range scan operation + NotDefined2, ///< Internal for debugging + NotDefined ///< Internal for debugging + }; +#endif + + /** + * Return lock mode for operation + */ + LockMode getLockMode() const { return theLockMode; } + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + void setAbortOption(Int8 ao) { m_abortOption = ao; } + + /** + * Set/get partition key + */ + void setPartitionId(Uint32 id); + void setPartitionHash(Uint32 key); + void setPartitionHash(const Uint64 *, Uint32 len); + Uint32 getPartitionId() const; +#endif +protected: + int handle_distribution_key(const Uint64 *, Uint32 len); +protected: +/****************************************************************************** + * These are the methods used to create and delete the NdbOperation objects. + *****************************************************************************/ + + bool needReply(); +/****************************************************************************** + * These methods are service routines used by the other NDB API classes. + *****************************************************************************/ +//-------------------------------------------------------------- +// Initialise after allocating operation to a transaction +//-------------------------------------------------------------- + int init(const class NdbTableImpl*, NdbTransaction* aCon); + void initInterpreter(); + + NdbOperation(Ndb* aNdb, Type aType = PrimaryKeyAccess); + virtual ~NdbOperation(); + void next(NdbOperation*); // Set next pointer + NdbOperation* next(); // Get next pointer +public: +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + const NdbOperation* next() const; + const NdbRecAttr* getFirstRecAttr() const; +#endif +protected: + + enum OperationStatus + { + Init, + OperationDefined, + TupleKeyDefined, + GetValue, + SetValue, + ExecInterpretedValue, + SetValueInterpreted, + FinalGetValue, + SubroutineExec, + SubroutineEnd, + WaitResponse, + WaitCommitResponse, + Finished, + ReceiveFinished + }; + + OperationStatus Status(); // Read the status information + + void Status(OperationStatus); // Set the status information + + void NdbCon(NdbTransaction*); // Set reference to connection + // object. + + virtual void release(); // Release all operations + // connected to + // the operations object. + void setStartIndicator(); + +/****************************************************************************** + * The methods below is the execution part of the NdbOperation + * class. This is where the NDB signals are sent and received. The + * operation can send TC[KEY/INDX]REQ, [INDX]ATTRINFO. + * It can receive TC[KEY/INDX]CONF, TC[KEY/INDX]REF, [INDX]ATTRINFO. + * When an operation is received in its fulness or a refuse message + * was sent, then the connection object is told about this situation. + *****************************************************************************/ + + int doSend(int ProcessorId, Uint32 lastFlag); + virtual int prepareSend(Uint32 TC_ConnectPtr, + Uint64 TransactionId); + virtual void setLastFlag(NdbApiSignal* signal, Uint32 lastFlag); + + int prepareSendInterpreted(); // Help routine to prepare* + + int receiveTCKEYREF(NdbApiSignal*); + + int checkMagicNumber(bool b = true); // Verify correct object + + int checkState_TransId(NdbApiSignal* aSignal); + +/****************************************************************************** + * These are support methods only used locally in this class. +******************************************************************************/ + + virtual int equal_impl(const NdbColumnImpl*,const char* aValue); + virtual NdbRecAttr* getValue_impl(const NdbColumnImpl*, char* aValue = 0); + int setValue(const NdbColumnImpl* anAttrObject, const char* aValue); + NdbBlob* getBlobHandle(NdbTransaction* aCon, const NdbColumnImpl* anAttrObject); + int incValue(const NdbColumnImpl* anAttrObject, Uint32 aValue); + int incValue(const NdbColumnImpl* anAttrObject, Uint64 aValue); + int subValue(const NdbColumnImpl* anAttrObject, Uint32 aValue); + int subValue(const NdbColumnImpl* anAttrObject, Uint64 aValue); + int read_attr(const NdbColumnImpl* anAttrObject, Uint32 RegDest); + int write_attr(const NdbColumnImpl* anAttrObject, Uint32 RegSource); + int branch_reg_reg(Uint32 type, Uint32, Uint32, Uint32); + int branch_col(Uint32 type, Uint32, const void *, Uint32, bool, Uint32 Label); + int branch_col_null(Uint32 type, Uint32 col, Uint32 Label); + + // Handle ATTRINFO signals + int insertATTRINFO(Uint32 aData); + int insertATTRINFOloop(const Uint32* aDataPtr, Uint32 aLength); + + int insertKEYINFO(const char* aValue, + Uint32 aStartPosition, + Uint32 aKeyLenInByte); + void reorderKEYINFO(); + + virtual void setErrorCode(int aErrorCode); + virtual void setErrorCodeAbort(int aErrorCode); + + void handleFailedAI_ElemLen(); // When not all attribute data + // were received + + int incCheck(const NdbColumnImpl* anAttrObject); + int initial_interpreterCheck(); + int intermediate_interpreterCheck(); + int read_attrCheck(const NdbColumnImpl* anAttrObject); + int write_attrCheck(const NdbColumnImpl* anAttrObject); + int labelCheck(); + int insertCall(Uint32 aCall); + int insertBranch(Uint32 aBranch); + + Uint32 ptr2int() { return theReceiver.getId(); }; + + // get table or index key from prepared signals + int getKeyFromTCREQ(Uint32* data, Uint32 & size); + +/****************************************************************************** + * These are the private variables that are defined in the operation objects. + *****************************************************************************/ + + Type m_type; + + NdbReceiver theReceiver; + + NdbError theError; // Errorcode + int theErrorLine; // Error line + + Ndb* theNdb; // Point back to the Ndb object. + NdbTransaction* theNdbCon; // Point back to the connection object. + NdbOperation* theNext; // Next pointer to operation. + + union { + NdbApiSignal* theTCREQ; // The TC[KEY/INDX]REQ signal object + NdbApiSignal* theSCAN_TABREQ; + }; + + NdbApiSignal* theFirstATTRINFO; // The first ATTRINFO signal object + NdbApiSignal* theCurrentATTRINFO; // The current ATTRINFO signal object + Uint32 theTotalCurrAI_Len; // The total number of attribute info + // words currently defined + Uint32 theAI_LenInCurrAI; // The number of words defined in the + // current ATTRINFO signal + NdbApiSignal* theLastKEYINFO; // The first KEYINFO signal object + + class NdbLabel* theFirstLabel; + class NdbLabel* theLastLabel; + class NdbBranch* theFirstBranch; + class NdbBranch* theLastBranch; + class NdbCall* theFirstCall; + class NdbCall* theLastCall; + class NdbSubroutine* theFirstSubroutine; + class NdbSubroutine* theLastSubroutine; + Uint32 theNoOfLabels; + Uint32 theNoOfSubroutines; + + Uint32* theKEYINFOptr; // Pointer to where to write KEYINFO + Uint32* theATTRINFOptr; // Pointer to where to write ATTRINFO + + const class NdbTableImpl* m_currentTable; // The current table + const class NdbTableImpl* m_accessTable; // Index table (== current for pk) + + // Set to TRUE when a tuple key attribute has been defined. + Uint32 theTupleKeyDefined[NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY][3]; + + Uint32 theTotalNrOfKeyWordInSignal; // The total number of + // keyword in signal. + + Uint32 theTupKeyLen; // Length of the tuple key in words + // left until done + Uint8 theNoOfTupKeyLeft; // The number of tuple key attributes + OperationType theOperationType; // Read Request, Update Req...... + + LockMode theLockMode; // Can be set to WRITE if read operation + OperationStatus theStatus; // The status of the operation. + + Uint32 theMagicNumber; // Magic number to verify that object + // is correct + Uint32 theScanInfo; // Scan info bits (take over flag etc) + Uint32 theDistributionKey; // Distribution Key size if used + + Uint32 theSubroutineSize; // Size of subroutines for interpretation + Uint32 theInitialReadSize; // Size of initial reads for interpretation + Uint32 theInterpretedSize; // Size of interpretation + Uint32 theFinalUpdateSize; // Size of final updates for interpretation + Uint32 theFinalReadSize; // Size of final reads for interpretation + + Uint8 theStartIndicator; // Indicator of whether start operation + Uint8 theCommitIndicator; // Indicator of whether commit operation + Uint8 theSimpleIndicator; // Indicator of whether simple operation + Uint8 theDirtyIndicator; // Indicator of whether dirty operation + Uint8 theInterpretIndicator; // Indicator of whether interpreted operation + Int8 theDistrKeyIndicator_; // Indicates whether distr. key is used + Uint8 m_no_disk_flag; + + Uint16 m_tcReqGSN; + Uint16 m_keyInfoGSN; + Uint16 m_attrInfoGSN; + + // Blobs in this operation + NdbBlob* theBlobList; + + /* + * Abort option per operation, used by blobs. Default -1. If set, + * overrides abort option on connection level. If set to IgnoreError, + * does not cause execute() to return failure. This is different from + * IgnoreError on connection level. + */ + Int8 m_abortOption; + + friend struct Ndb_free_list_t<NdbOperation>; +}; + +#ifdef NDB_NO_DROPPED_SIGNAL +#include <stdlib.h> +#endif + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + +inline +int +NdbOperation::checkMagicNumber(bool b) +{ + if (theMagicNumber != 0xABCDEF01){ +#ifdef NDB_NO_DROPPED_SIGNAL + if(b) abort(); +#endif + return -1; + } + return 0; +} + +inline +void +NdbOperation::setStartIndicator() +{ + theStartIndicator = 1; +} + +inline +int +NdbOperation::getNdbErrorLine() +{ + return theErrorLine; +} + +/****************************************************************************** +void next(NdbOperation* aNdbOperation); + +Parameters: aNdbOperation: Pointers to the NdbOperation object. +Remark: Set the next variable of the operation object. +******************************************************************************/ +inline +void +NdbOperation::next(NdbOperation* aNdbOperation) +{ + theNext = aNdbOperation; +} + +/****************************************************************************** +NdbOperation* next(); + +Return Value: Return next pointer to NdbOperation object. +Remark: Get the next variable of the operation object. +******************************************************************************/ +inline +NdbOperation* +NdbOperation::next() +{ + return theNext; +} + +inline +const NdbOperation* +NdbOperation::next() const +{ + return theNext; +} + +inline +const NdbRecAttr* +NdbOperation::getFirstRecAttr() const +{ + return theReceiver.theFirstRecAttr; +} + +/****************************************************************************** +Type getType() + +Return Value Return the Type. +Remark: Gets type of access. +******************************************************************************/ +inline +const NdbOperation::Type +NdbOperation::getType() const +{ + return m_type; +} + +/****************************************************************************** +OperationStatus Status(); + +Return Value Return the OperationStatus. +Parameters: aStatus: The status. +Remark: Sets Operation status. +******************************************************************************/ +inline +NdbOperation::OperationStatus +NdbOperation::Status() +{ + return theStatus; +} + +/****************************************************************************** +void Status(OperationStatus aStatus); + +Parameters: aStatus: The status. +Remark: Sets Operation + status. +******************************************************************************/ +inline +void +NdbOperation::Status( OperationStatus aStatus ) +{ + theStatus = aStatus; +} + +/****************************************************************************** +void NdbCon(NdbTransaction* aNdbCon); + +Parameters: aNdbCon: Pointers to NdbTransaction object. +Remark: Set the reference to the connection in the operation object. +******************************************************************************/ +inline +void +NdbOperation::NdbCon(NdbTransaction* aNdbCon) +{ + theNdbCon = aNdbCon; +} + +inline +int +NdbOperation::equal(const char* anAttrName, const char* aValue, Uint32 len) +{ + return equal(anAttrName, aValue); +} + +inline +int +NdbOperation::equal(const char* anAttrName, Int32 aPar) +{ + return equal(anAttrName, (const char*)&aPar, (Uint32)4); +} + +inline +int +NdbOperation::equal(const char* anAttrName, Uint32 aPar) +{ + return equal(anAttrName, (const char*)&aPar, (Uint32)4); +} + +inline +int +NdbOperation::equal(const char* anAttrName, Int64 aPar) +{ + return equal(anAttrName, (const char*)&aPar, (Uint32)8); +} + +inline +int +NdbOperation::equal(const char* anAttrName, Uint64 aPar) +{ + return equal(anAttrName, (const char*)&aPar, (Uint32)8); +} + +inline +int +NdbOperation::equal(Uint32 anAttrId, const char* aValue, Uint32 len) +{ + return equal(anAttrId, aValue); +} + +inline +int +NdbOperation::equal(Uint32 anAttrId, Int32 aPar) +{ + return equal(anAttrId, (const char*)&aPar, (Uint32)4); +} + +inline +int +NdbOperation::equal(Uint32 anAttrId, Uint32 aPar) +{ + return equal(anAttrId, (const char*)&aPar, (Uint32)4); +} + +inline +int +NdbOperation::equal(Uint32 anAttrId, Int64 aPar) +{ + return equal(anAttrId, (const char*)&aPar, (Uint32)8); +} + +inline +int +NdbOperation::equal(Uint32 anAttrId, Uint64 aPar) +{ + return equal(anAttrId, (const char*)&aPar, (Uint32)8); +} + +inline +int +NdbOperation::setValue(const char* anAttrName, const char* aValue, Uint32 len) +{ + return setValue(anAttrName, aValue); +} + +inline +int +NdbOperation::setValue(const char* anAttrName, Int32 aPar) +{ + return setValue(anAttrName, (const char*)&aPar, (Uint32)4); +} + +inline +int +NdbOperation::setValue(const char* anAttrName, Uint32 aPar) +{ + return setValue(anAttrName, (const char*)&aPar, (Uint32)4); +} + +inline +int +NdbOperation::setValue(const char* anAttrName, Int64 aPar) +{ + return setValue(anAttrName, (const char*)&aPar, (Uint32)8); +} + +inline +int +NdbOperation::setValue(const char* anAttrName, Uint64 aPar) +{ + return setValue(anAttrName, (const char*)&aPar, (Uint32)8); +} + +inline +int +NdbOperation::setValue(const char* anAttrName, float aPar) +{ + return setValue(anAttrName, (const char*)&aPar, (Uint32)4); +} + +inline +int +NdbOperation::setValue(const char* anAttrName, double aPar) +{ + return setValue(anAttrName, (const char*)&aPar, (Uint32)8); +} + +inline +int +NdbOperation::setValue(Uint32 anAttrId, const char* aValue, Uint32 len) +{ + return setValue(anAttrId, aValue); +} + +inline +int +NdbOperation::setValue(Uint32 anAttrId, Int32 aPar) +{ + return setValue(anAttrId, (const char*)&aPar, (Uint32)4); +} + +inline +int +NdbOperation::setValue(Uint32 anAttrId, Uint32 aPar) +{ + return setValue(anAttrId, (const char*)&aPar, (Uint32)4); +} + +inline +int +NdbOperation::setValue(Uint32 anAttrId, Int64 aPar) +{ + return setValue(anAttrId, (const char*)&aPar, (Uint32)8); +} + +inline +int +NdbOperation::setValue(Uint32 anAttrId, Uint64 aPar) +{ + return setValue(anAttrId, (const char*)&aPar, (Uint32)8); +} + +inline +int +NdbOperation::setValue(Uint32 anAttrId, float aPar) +{ + return setValue(anAttrId, (char*)&aPar, (Uint32)4); +} + +inline +int +NdbOperation::setValue(Uint32 anAttrId, double aPar) +{ + return setValue(anAttrId, (const char*)&aPar, (Uint32)8); +} + +#endif // doxygen + +#endif diff --git a/storage/ndb/include/ndbapi/NdbPool.hpp b/storage/ndb/include/ndbapi/NdbPool.hpp new file mode 100644 index 00000000000..64cba5a008c --- /dev/null +++ b/storage/ndb/include/ndbapi/NdbPool.hpp @@ -0,0 +1,35 @@ +/* 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 */ + +class Ndb; +class NdbPool; + +bool +create_instance(Uint32 max_ndb_objects, + Uint32 no_conn_obj, + Uint32 init_no_ndb_objects); + +void +drop_instance(); + +Ndb* +get_ndb_object(Uint32 &hint_id, + const char* a_catalog_name, + const char* a_schema_name); + +void +return_ndb_object(Ndb* returned_object, Uint32 id); + diff --git a/storage/ndb/include/ndbapi/NdbRecAttr.hpp b/storage/ndb/include/ndbapi/NdbRecAttr.hpp new file mode 100644 index 00000000000..5d9b0832e18 --- /dev/null +++ b/storage/ndb/include/ndbapi/NdbRecAttr.hpp @@ -0,0 +1,416 @@ +/* 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 */ + +#ifndef NdbRecAttr_H +#define NdbRecAttr_H + +#include "NdbDictionary.hpp" +#include "Ndb.hpp" + +class NdbOperation; + +/** + * @class NdbRecAttr + * @brief Contains value of an attribute. + * + * NdbRecAttr objects are used to store the attribute value + * after retrieving the value from the NDB Cluster using the method + * NdbOperation::getValue. The objects are allocated by the NDB API. + * An example application program follows: + * + * @code + * MyRecAttr = MyOperation->getValue("ATTR2", NULL); + * if (MyRecAttr == NULL) goto error; + * + * if (MyTransaction->execute(Commit) == -1) goto error; + * + * ndbout << MyRecAttr->u_32_value(); + * @endcode + * For more examples, see + * @ref ndbapi_simple.cpp. + * + * @note The NdbRecAttr object is instantiated with its value when + * NdbTransaction::execute is called. Before this, the value is + * undefined. (NdbRecAttr::isNULL can be used to check + * if the value is defined or not.) + * This means that an NdbRecAttr object only has valid information + * between the time of calling NdbTransaction::execute and + * the time of Ndb::closeTransaction. + * The value of the null indicator is -1 until the + * NdbTransaction::execute method have been called. + * + * For simple types, there are methods which directly getting the value + * from the NdbRecAttr object. + * + * To get a reference to the value, there are two methods: + * NdbRecAttr::aRef (memory is released by NDB API) and + * NdbRecAttr::getAttributeObject (memory must be released + * by application program). + * The two methods may return different pointers. + * + * There are also methods to check attribute type, attribute size and + * array size. + * The method NdbRecAttr::arraySize returns the number of elements in the + * array (where each element is of size given by NdbRecAttr::attrSize). + * The NdbRecAttr::arraySize method is needed when reading variable-sized + * attributes. + * + * @note Variable-sized attributes are not yet supported. + */ +class NdbRecAttr +{ +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + friend class NdbOperation; + friend class NdbIndexScanOperation; + friend class NdbEventOperationImpl; + friend class NdbReceiver; + friend class Ndb; + friend class NdbOut& operator<<(class NdbOut&, const class AttributeS&); +#endif + +public: + /** + * @name Getting meta information + * @{ + */ + const NdbDictionary::Column * getColumn() const; + + /** + * Get type of column + * @return Data type of the column + */ + NdbDictionary::Column::Type getType() const; + + /** + * Get attribute (element) size in bytes. + * + */ + Uint32 get_size_in_bytes() const { return m_size_in_bytes; } + + /** @} *********************************************************************/ + /** + * @name Getting stored value + * @{ + */ + + /** + * Check if attribute value is NULL. + * + * @return -1 = Not defined (Failure or + * NdbTransaction::execute not yet called).<br> + * 0 = Attribute value is defined, but not equal to NULL.<br> + * 1 = Attribute value is defined and equal to NULL. + */ + int isNULL() const; + + /** + * Get value stored in NdbRecAttr object. + * + * @return 64 bit long value. + */ + Int64 int64_value() const; + + /** + * Get value stored in NdbRecAttr object. + * + * @return 32 bit int value. + */ + Int32 int32_value() const; + + /** + * Get value stored in NdbRecAttr object. + * + * @return Short value. + */ + short short_value() const; + + /** + * Get value stored in NdbRecAttr object. + * + * @return Char value. + */ + char char_value() const; + + /** + * Get value stored in NdbRecAttr object. + * + * @return 64 bit unsigned value. + */ + Uint64 u_64_value() const; + + /** + * Get value stored in NdbRecAttr object. + * + * @return 32 bit unsigned value. + */ + Uint32 u_32_value() const; + + /** + * Get value stored in NdbRecAttr object. + * + * @return Unsigned short value. + */ + Uint16 u_short_value() const; + + /** + * Get value stored in NdbRecAttr object. + * + * @return Unsigned char value. + */ + Uint8 u_char_value() const; + + /** + * Get value stored in NdbRecAttr object. + * + * @return Float value. + */ + float float_value() const; + + /** + * Get value stored in NdbRecAttr object. + * + * @return Double value. + */ + double double_value() const; + + /** @} *********************************************************************/ + /** + * @name Getting reference to stored value + * @{ + */ + + /** + * Get reference to attribute value. + * + * Returns a char*-pointer to the value. + * The pointer is aligned appropriately for the data type. + * The memory is released when Ndb::closeTransaction is executed + * for the transaction which read the value. + * + * @note The memory is released by NDB API. + * + * @note The pointer to the attribute value stored in an NdbRecAttr + * object (i.e. the pointer returned by aRef) is constant. + * This means that this method can be called anytime after + * NdbOperation::getValue has been called. + * + * @return Pointer to attribute value. + */ + char* aRef() const; + + /** @} *********************************************************************/ + + /** + * Make a copy of RecAttr object including all data. + * + * @note Copy needs to be deleted by application program. + */ + NdbRecAttr * clone() const; + + /** + * Destructor + * + * @note You should only delete RecAttr-copies, + * i.e. objects that has been cloned. + */ + ~NdbRecAttr(); + +public: +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + const NdbRecAttr* next() const; +#endif +private: + + Uint32 attrId() const; /* Get attribute id */ + bool setNULL(); /* Set NULL indicator */ + void setUNDEFINED(); // + + bool receive_data(const Uint32*, Uint32); + + void release(); /* Release memory if allocated */ + void init(); /* Initialise object when allocated */ + + NdbRecAttr(Ndb*); + void next(NdbRecAttr* aRecAttr); + NdbRecAttr* next(); + + int setup(const class NdbDictionary::Column* col, char* aValue); + int setup(const class NdbColumnImpl* anAttrInfo, char* aValue); + /* Set up attributes and buffers */ + bool copyoutRequired() const; /* Need to copy data to application */ + void copyout(); /* Copy from storage to application */ + + Uint64 theStorage[4]; /* The data storage here if <= 32 bytes */ + Uint64* theStorageX; /* The data storage here if > 32 bytes */ + char* theValue; /* The data storage in the application */ + void* theRef; /* Pointer to one of above */ + + NdbRecAttr* theNext; /* Next pointer */ + Uint32 theAttrId; /* The attribute id */ + + Int32 m_size_in_bytes; + const NdbDictionary::Column* m_column; + + friend struct Ndb_free_list_t<NdbRecAttr>; +}; + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + +inline +NdbDictionary::Column::Type +NdbRecAttr::getType() const { + return m_column->getType(); +} + +inline +const NdbDictionary::Column * +NdbRecAttr::getColumn() const { + return m_column; +} + +inline +Int32 +NdbRecAttr::int32_value() const +{ + return *(Int32*)theRef; +} + +inline +short +NdbRecAttr::short_value() const +{ + return *(short*)theRef; +} + +inline +char +NdbRecAttr::char_value() const +{ + return *(char*)theRef; +} + +inline +Uint32 +NdbRecAttr::u_32_value() const +{ + return *(Uint32*)theRef; +} + +inline +Uint16 +NdbRecAttr::u_short_value() const +{ + return *(Uint16*)theRef; +} + +inline +Uint8 +NdbRecAttr::u_char_value() const +{ + return *(Uint8*)theRef; +} + +inline +void +NdbRecAttr::release() +{ + if (theStorageX != 0) { + delete [] theStorageX; + theStorageX = 0; + } +} + +inline +void +NdbRecAttr::init() +{ + theStorageX = 0; + theValue = 0; + theRef = 0; + theNext = 0; + theAttrId = 0xFFFF; +} + +inline +void +NdbRecAttr::next(NdbRecAttr* aRecAttr) +{ + theNext = aRecAttr; +} + +inline +NdbRecAttr* +NdbRecAttr::next() +{ + return theNext; +} + +inline +const NdbRecAttr* +NdbRecAttr::next() const +{ + return theNext; +} + +inline +char* +NdbRecAttr::aRef() const +{ + return (char*)theRef; +} + +inline +bool +NdbRecAttr::copyoutRequired() const +{ + return theRef != theValue && theValue != 0; +} + +inline +Uint32 +NdbRecAttr::attrId() const +{ + return theAttrId; +} + +inline +bool +NdbRecAttr::setNULL() +{ + m_size_in_bytes= 0; + return true; +} + +inline +int +NdbRecAttr::isNULL() const +{ + return m_size_in_bytes == 0 ? 1 : (m_size_in_bytes > 0 ? 0 : -1); +} + +inline +void +NdbRecAttr::setUNDEFINED() +{ + m_size_in_bytes= -1; +} + +class NdbOut& operator <<(class NdbOut&, const NdbRecAttr &); + +#endif // ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + +#endif + diff --git a/storage/ndb/include/ndbapi/NdbReceiver.hpp b/storage/ndb/include/ndbapi/NdbReceiver.hpp new file mode 100644 index 00000000000..ff6debc7fd3 --- /dev/null +++ b/storage/ndb/include/ndbapi/NdbReceiver.hpp @@ -0,0 +1,150 @@ +/* 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 */ + +#ifndef NdbReceiver_H +#define NdbReceiver_H +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL // Not part of public interface + +#include <ndb_types.h> + +class Ndb; +class NdbTransaction; + +class NdbReceiver +{ + friend class Ndb; + friend class NdbOperation; + friend class NdbScanOperation; + friend class NdbIndexOperation; + friend class NdbIndexScanOperation; + friend class NdbTransaction; +public: + enum ReceiverType { NDB_UNINITIALIZED, + NDB_OPERATION = 1, + NDB_SCANRECEIVER = 2, + NDB_INDEX_OPERATION = 3 + }; + + NdbReceiver(Ndb *aNdb); + void init(ReceiverType type, void* owner); + void release(); + ~NdbReceiver(); + + Uint32 getId(){ + return m_id; + } + + ReceiverType getType(){ + return m_type; + } + + inline NdbTransaction * getTransaction(); + void* getOwner(){ + return m_owner; + } + + bool checkMagicNumber() const; + + inline void next(NdbReceiver* next) { m_next = next;} + inline NdbReceiver* next() { return m_next; } + + void setErrorCode(int); +private: + Uint32 theMagicNumber; + Ndb* m_ndb; + Uint32 m_id; + Uint32 m_tcPtrI; + Uint32 m_hidden_count; + ReceiverType m_type; + void* m_owner; + NdbReceiver* m_next; + + /** + * At setup + */ + class NdbRecAttr * getValue(const class NdbColumnImpl*, char * user_dst_ptr); + void do_get_value(NdbReceiver*, Uint32 rows, Uint32 key_size, Uint32 range); + void prepareSend(); + void calculate_batch_size(Uint32, Uint32, Uint32&, Uint32&, Uint32&); + + int execKEYINFO20(Uint32 info, const Uint32* ptr, Uint32 len); + int execTRANSID_AI(const Uint32* ptr, Uint32 len); + int execTCOPCONF(Uint32 len); + int execSCANOPCONF(Uint32 tcPtrI, Uint32 len, Uint32 rows); + class NdbRecAttr* theFirstRecAttr; + class NdbRecAttr* theCurrentRecAttr; + class NdbRecAttr** m_rows; + + Uint32 m_list_index; // When using multiple + Uint32 m_current_row; + Uint32 m_result_rows; + Uint32 m_defined_rows; + + Uint32 m_expected_result_length; + Uint32 m_received_result_length; + + bool nextResult() const { return m_current_row < m_result_rows; } + NdbRecAttr* copyout(NdbReceiver&); +}; + +#ifdef NDB_NO_DROPPED_SIGNAL +#include <stdlib.h> +#endif + +inline +bool +NdbReceiver::checkMagicNumber() const { + bool retVal = (theMagicNumber == 0x11223344); +#ifdef NDB_NO_DROPPED_SIGNAL + if(!retVal){ + abort(); + } +#endif + return retVal; +} + +inline +void +NdbReceiver::prepareSend(){ + m_current_row = 0; + m_received_result_length = 0; + m_expected_result_length = 0; + theCurrentRecAttr = theFirstRecAttr; +} + +inline +int +NdbReceiver::execTCOPCONF(Uint32 len){ + Uint32 tmp = m_received_result_length; + m_expected_result_length = len; +#ifdef assert + assert(!(tmp && !len)); +#endif + return ((bool)len ^ (bool)tmp ? 0 : 1); +} + +inline +int +NdbReceiver::execSCANOPCONF(Uint32 tcPtrI, Uint32 len, Uint32 rows){ + m_tcPtrI = tcPtrI; + m_result_rows = rows; + Uint32 tmp = m_received_result_length; + m_expected_result_length = len; + return (tmp == len ? 1 : 0); +} + +#endif // DOXYGEN_SHOULD_SKIP_INTERNAL +#endif diff --git a/storage/ndb/include/ndbapi/NdbScanFilter.hpp b/storage/ndb/include/ndbapi/NdbScanFilter.hpp new file mode 100644 index 00000000000..b5457bab99b --- /dev/null +++ b/storage/ndb/include/ndbapi/NdbScanFilter.hpp @@ -0,0 +1,178 @@ +/* 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 */ + +#ifndef NDB_SCAN_FILTER_HPP +#define NDB_SCAN_FILTER_HPP + +#include <ndb_types.h> + +/** + * @class NdbScanFilter + * @brief A simple way to specify filters for scan operations + * + * @note This filter interface is under development and may change in + * the future! + * + */ +class NdbScanFilter { +public: + /** + * Constructor + * @param op The NdbOperation that the filter belongs to (is applied to). + */ + NdbScanFilter(class NdbOperation * op); + ~NdbScanFilter(); + + /** + * Group operators + */ + enum Group { + AND = 1, ///< (x1 AND x2 AND x3) + OR = 2, ///< (x1 OR x2 OR X3) + NAND = 3, ///< NOT (x1 AND x2 AND x3) + NOR = 4 ///< NOT (x1 OR x2 OR x3) + }; + + enum BinaryCondition + { + COND_LE = 0, ///< lower bound + COND_LT = 1, ///< lower bound, strict + COND_GE = 2, ///< upper bound + COND_GT = 3, ///< upper bound, strict + COND_EQ = 4, ///< equality + COND_NE = 5, ///< not equal + COND_LIKE = 6, ///< like + COND_NOT_LIKE = 7 ///< not like + }; + + /** + * @name Grouping + * @{ + */ + + /** + * Begin of compound. + * ®return 0 if successful, -1 otherwize + */ + int begin(Group group = AND); + + /** + * End of compound. + * ®return 0 if successful, -1 otherwize + */ + int end(); + + /** @} *********************************************************************/ + + /** + * <i>Explanation missing</i> + */ + int istrue(); + + /** + * <i>Explanation missing</i> + */ + int isfalse(); + + /** + * Compare column <b>ColId</b> with <b>val</b> + */ + int cmp(BinaryCondition cond, int ColId, const void *val, Uint32 len = 0); + + /** + * @name Integer Comparators + * @{ + */ + /** Compare column value with integer for equal + * ®return 0 if successful, -1 otherwize + */ + int eq(int ColId, Uint32 value) { return cmp(COND_EQ, ColId, &value, 4);} + + /** Compare column value with integer for not equal. + * ®return 0 if successful, -1 otherwize + */ + int ne(int ColId, Uint32 value) { return cmp(COND_NE, ColId, &value, 4);} + /** Compare column value with integer for less than. + * ®return 0 if successful, -1 otherwize + */ + int lt(int ColId, Uint32 value) { return cmp(COND_LT, ColId, &value, 4);} + /** Compare column value with integer for less than or equal. + * ®return 0 if successful, -1 otherwize + */ + int le(int ColId, Uint32 value) { return cmp(COND_LE, ColId, &value, 4);} + /** Compare column value with integer for greater than. + * ®return 0 if successful, -1 otherwize + */ + int gt(int ColId, Uint32 value) { return cmp(COND_GT, ColId, &value, 4);} + /** Compare column value with integer for greater than or equal. + * ®return 0 if successful, -1 otherwize + */ + int ge(int ColId, Uint32 value) { return cmp(COND_GE, ColId, &value, 4);} + + /** Compare column value with integer for equal. 64-bit. + * ®return 0 if successful, -1 otherwize + */ + int eq(int ColId, Uint64 value) { return cmp(COND_EQ, ColId, &value, 8);} + /** Compare column value with integer for not equal. 64-bit. + * ®return 0 if successful, -1 otherwize + */ + int ne(int ColId, Uint64 value) { return cmp(COND_NE, ColId, &value, 8);} + /** Compare column value with integer for less than. 64-bit. + * ®return 0 if successful, -1 otherwize + */ + int lt(int ColId, Uint64 value) { return cmp(COND_LT, ColId, &value, 8);} + /** Compare column value with integer for less than or equal. 64-bit. + * ®return 0 if successful, -1 otherwize + */ + int le(int ColId, Uint64 value) { return cmp(COND_LE, ColId, &value, 8);} + /** Compare column value with integer for greater than. 64-bit. + * ®return 0 if successful, -1 otherwize + */ + int gt(int ColId, Uint64 value) { return cmp(COND_GT, ColId, &value, 8);} + /** Compare column value with integer for greater than or equal. 64-bit. + * ®return 0 if successful, -1 otherwize + */ + int ge(int ColId, Uint64 value) { return cmp(COND_GE, ColId, &value, 8);} + /** @} *********************************************************************/ + + /** Check if column value is NULL */ + int isnull(int ColId); + /** Check if column value is non-NULL */ + int isnotnull(int ColId); + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + /** + * Like comparison operator. + * ®return 0 if successful, -1 otherwize + */ + int like(int ColId, const char * val, Uint32 len, bool nopad=false); + /** + * Notlike comparison operator. + * ®return 0 if successful, -1 otherwize + */ + int notlike(int ColId, const char * val, Uint32 len, bool nopad=false); + /** @} *********************************************************************/ +#endif + +private: +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + friend class NdbScanFilterImpl; +#endif + class NdbScanFilterImpl & m_impl; + NdbScanFilter& operator=(const NdbScanFilter&); ///< Defined not implemented +}; + +#endif diff --git a/storage/ndb/include/ndbapi/NdbScanOperation.hpp b/storage/ndb/include/ndbapi/NdbScanOperation.hpp new file mode 100644 index 00000000000..209cd7e29b8 --- /dev/null +++ b/storage/ndb/include/ndbapi/NdbScanOperation.hpp @@ -0,0 +1,313 @@ +/* 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 */ + +#ifndef NdbScanOperation_H +#define NdbScanOperation_H + +#include <NdbOperation.hpp> + +class NdbBlob; +class NdbResultSet; +class PollGuard; + +/** + * @class NdbScanOperation + * @brief Class of scan operations for use in transactions. + */ +class NdbScanOperation : public NdbOperation { +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + friend class Ndb; + friend class NdbTransaction; + friend class NdbResultSet; + friend class NdbOperation; + friend class NdbBlob; +#endif + +public: + /** + * Scan flags. OR-ed together and passed as second argument to + * readTuples. + */ + enum ScanFlag { + SF_TupScan = (1 << 16), // scan TUP order + SF_DiskScan = (2 << 16), // scan in DISK order + SF_OrderBy = (1 << 24), // index scan in order + SF_Descending = (2 << 24), // index scan in descending order + SF_ReadRangeNo = (4 << 24), // enable @ref get_range_no + SF_KeyInfo = 1 // request KeyInfo to be sent back + }; + + /** + * readTuples + * + * @param lock_mode Lock mode + * @param scan_flags see @ref ScanFlag + * @param parallel No of fragments to scan in parallel (0=max) + */ + virtual + int readTuples(LockMode lock_mode = LM_Read, + Uint32 scan_flags = 0, + Uint32 parallel = 0, + Uint32 batch = 0); + +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + /** + * readTuples + * @param lock_mode Lock mode + * @param batch No of rows to fetch from each fragment at a time + * @param parallel No of fragments to scan in parallell + * @note specifying 0 for batch and parallell means max performance + */ +#ifdef ndb_readtuples_impossible_overload + int readTuples(LockMode lock_mode = LM_Read, + Uint32 batch = 0, Uint32 parallel = 0, bool keyinfo = false); +#endif + + inline int readTuples(int parallell){ + return readTuples(LM_Read, 0, parallell); + } + + inline int readTuplesExclusive(int parallell = 0){ + return readTuples(LM_Exclusive, 0, parallell); + } +#endif + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + NdbBlob* getBlobHandle(const char* anAttrName); + NdbBlob* getBlobHandle(Uint32 anAttrId); +#endif + + /** + * Get the next tuple in a scan transaction. + * + * After each call to nextResult + * the buffers and NdbRecAttr objects defined in + * NdbOperation::getValue are updated with values + * from the scanned tuple. + * + * @param fetchAllowed If set to false, then fetching is disabled + * @param forceSend If true send will occur immediately (see @ref secAdapt) + * + * The NDB API will contact the NDB Kernel for more tuples + * when necessary to do so unless you set the fetchAllowed + * to false. + * This will force NDB to process any records it + * already has in it's caches. When there are no more cached + * records it will return 2. You must then call nextResult + * with fetchAllowed = true in order to contact NDB for more + * records. + * + * fetchAllowed = false is useful when you want to update or + * delete all the records fetched in one transaction(This will save a + * lot of round trip time and make updates or deletes of scanned + * records a lot faster). + * While nextResult(false) + * returns 0 take over the record to another transaction. When + * nextResult(false) returns 2 you must execute and commit the other + * transaction. This will cause the locks to be transferred to the + * other transaction, updates or deletes will be made and then the + * locks will be released. + * After that, call nextResult(true) which will fetch new records and + * cache them in the NdbApi. + * + * @note If you don't take over the records to another transaction the + * locks on those records will be released the next time NDB Kernel + * is contacted for more records. + * + * @note Please contact for examples of efficient scan + * updates and deletes. + * + * @note See ndb/examples/ndbapi_scan_example for usage. + * + * @return + * - -1: if unsuccessful,<br> + * - 0: if another tuple was received, and<br> + * - 1: if there are no more tuples to scan. + * - 2: if there are no more cached records in NdbApi + */ + int nextResult(bool fetchAllowed = true, bool forceSend = false); + + /** + * Close scan + */ + void close(bool forceSend = false, bool releaseOp = false); + + /** + * Lock current tuple + * + * @return an NdbOperation or NULL. + */ + NdbOperation* lockCurrentTuple(); + /** + * Lock current tuple + * + * @param lockTrans Transaction that should perform the lock + * + * @return an NdbOperation or NULL. + */ + NdbOperation* lockCurrentTuple(NdbTransaction* lockTrans); + /** + * Update current tuple + * + * @return an NdbOperation or NULL. + */ + NdbOperation* updateCurrentTuple(); + /** + * Update current tuple + * + * @param updateTrans Transaction that should perform the update + * + * @return an NdbOperation or NULL. + */ + NdbOperation* updateCurrentTuple(NdbTransaction* updateTrans); + + /** + * Delete current tuple + * @return 0 on success or -1 on failure + */ + int deleteCurrentTuple(); + /** + * Delete current tuple + * + * @param takeOverTransaction Transaction that should perform the delete + * + * @return 0 on success or -1 on failure + */ + int deleteCurrentTuple(NdbTransaction* takeOverTransaction); + + /** + * Restart scan with exactly the same + * getValues and search conditions + */ + int restart(bool forceSend = false); + +protected: + NdbScanOperation(Ndb* aNdb, + NdbOperation::Type aType = NdbOperation::TableScan); + virtual ~NdbScanOperation(); + + int nextResultImpl(bool fetchAllowed = true, bool forceSend = false); + virtual void release(); + + int close_impl(class TransporterFacade*, bool forceSend, + PollGuard *poll_guard); + + // Overloaded methods from NdbCursorOperation + int executeCursor(int ProcessorId); + + // Overloaded private methods from NdbOperation + int init(const NdbTableImpl* tab, NdbTransaction*); + int prepareSend(Uint32 TC_ConnectPtr, Uint64 TransactionId); + int doSend(int ProcessorId); + + virtual void setErrorCode(int aErrorCode); + virtual void setErrorCodeAbort(int aErrorCode); + + NdbTransaction *m_transConnection; + + // Scan related variables + Uint32 theParallelism; + Uint32 m_keyInfo; + + int getFirstATTRINFOScan(); + int doSendScan(int ProcessorId); + int prepareSendScan(Uint32 TC_ConnectPtr, Uint64 TransactionId); + + int fix_receivers(Uint32 parallel); + void reset_receivers(Uint32 parallel, Uint32 ordered); + Uint32* m_array; // containing all arrays below + Uint32 m_allocated_receivers; + NdbReceiver** m_receivers; // All receivers + + Uint32* m_prepared_receivers; // These are to be sent + + /** + * owned by API/user thread + */ + Uint32 m_current_api_receiver; + Uint32 m_api_receivers_count; + NdbReceiver** m_api_receivers; // These are currently used by api + + /** + * owned by receiver thread + */ + Uint32 m_conf_receivers_count; // NOTE needs mutex to access + NdbReceiver** m_conf_receivers; // receive thread puts them here + + /** + * owned by receiver thread + */ + Uint32 m_sent_receivers_count; // NOTE needs mutex to access + NdbReceiver** m_sent_receivers; // receive thread puts them here + + int send_next_scan(Uint32 cnt, bool close); + void receiver_delivered(NdbReceiver*); + void receiver_completed(NdbReceiver*); + void execCLOSE_SCAN_REP(); + + int getKeyFromKEYINFO20(Uint32* data, Uint32 & size); + NdbOperation* takeOverScanOp(OperationType opType, NdbTransaction*); + + bool m_ordered; + bool m_descending; + Uint32 m_read_range_no; + NdbRecAttr *m_curr_row; // Pointer to last returned row + bool m_executed; // Marker if operation should be released at close +}; + +inline +NdbOperation* +NdbScanOperation::lockCurrentTuple(){ + return lockCurrentTuple(m_transConnection); +} + +inline +NdbOperation* +NdbScanOperation::lockCurrentTuple(NdbTransaction* takeOverTrans){ + return takeOverScanOp(NdbOperation::ReadRequest, + takeOverTrans); +} + +inline +NdbOperation* +NdbScanOperation::updateCurrentTuple(){ + return updateCurrentTuple(m_transConnection); +} + +inline +NdbOperation* +NdbScanOperation::updateCurrentTuple(NdbTransaction* takeOverTrans){ + return takeOverScanOp(NdbOperation::UpdateRequest, + takeOverTrans); +} + +inline +int +NdbScanOperation::deleteCurrentTuple(){ + return deleteCurrentTuple(m_transConnection); +} + +inline +int +NdbScanOperation::deleteCurrentTuple(NdbTransaction * takeOverTrans){ + void * res = takeOverScanOp(NdbOperation::DeleteRequest, + takeOverTrans); + if(res == 0) + return -1; + return 0; +} + +#endif diff --git a/storage/ndb/include/ndbapi/NdbTransaction.hpp b/storage/ndb/include/ndbapi/NdbTransaction.hpp new file mode 100644 index 00000000000..8d367f1620a --- /dev/null +++ b/storage/ndb/include/ndbapi/NdbTransaction.hpp @@ -0,0 +1,1060 @@ +/* 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 */ + +#ifndef NdbTransaction_H +#define NdbTransaction_H + +#include <ndb_types.h> +#include "NdbError.hpp" +#include "NdbDictionary.hpp" +#include "Ndb.hpp" + +class NdbTransaction; +class NdbOperation; +class NdbScanOperation; +class NdbIndexScanOperation; +class NdbIndexOperation; +class NdbApiSignal; +class Ndb; +class NdbBlob; + +#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 { + CommitIfFailFree= 0, + TryCommit= 0, + AbortOnError= 0, + CommitAsMuchAsPossible= 2, + AO_IgnoreError= 2 +}; +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 NdbTransaction +{ +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + friend class Ndb; + friend class NdbOperation; + friend class NdbScanOperation; + friend class NdbIndexOperation; + friend class NdbIndexScanOperation; + friend class NdbBlob; + friend class ha_ndbcluster; +#endif + +public: + + /** + * Commit type of transaction + */ + enum AbortOption { + AbortOnError= ///< Abort transaction on failed operation +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + ::AbortOnError +#endif + ,AO_IgnoreError= ///< Transaction continues on failed operation +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + ::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_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 index name. + * @param aTableName The table name. + * @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); + + /** + * @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 + * IgnoreError - Accept failing operations + * @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. + */ + int execute(ExecType execType, + AbortOption abortOption = AbortOnError, + int force = 0 ); +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + int execute(::ExecType execType, + ::AbortOption abortOption = ::AbortOnError, + int force = 0 ) + { return execute ((ExecType)execType,(AbortOption)abortOption,force); } +#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 + */ + void executeAsynchPrepare(ExecType execType, + NdbAsynchCallback callback, + void* anyObject, + AbortOption abortOption = AbortOnError); +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + void executeAsynchPrepare(::ExecType execType, + NdbAsynchCallback callback, + void* anyObject, + ::AbortOption abortOption = ::AbortOnError) + { executeAsynchPrepare((ExecType)execType, callback, anyObject, + (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. + */ + void executeAsynch(ExecType aTypeOfExec, + NdbAsynchCallback aCallback, + void* anyObject, + AbortOption abortOption = AbortOnError); +#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED + void executeAsynch(::ExecType aTypeOfExec, + NdbAsynchCallback aCallback, + void* anyObject, + ::AbortOption abortOption= ::AbortOnError) + { executeAsynch((ExecType)aTypeOfExec, aCallback, anyObject, + (AbortOption)abortOption); } +#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 GCI of transaction or -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(); + + /** + * 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. + */ + NdbOperation* getNdbErrorOperation(); + + /** + * Get the method number where the latest error occured. + * + * @return Line number where latest error occured. + */ + 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 + +private: + /** + * Release completed operations + */ + void releaseCompletedOperations(); + + 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(); + + void init(); // Initialize connection object for new transaction + + int executeNoBlobs(ExecType execType, + AbortOption abortOption = AbortOnError, + 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 receiveDIHNDBTAMPER(NdbApiSignal* anApiSignal); + int receiveTCSEIZECONF(NdbApiSignal* anApiSignal); + int receiveTCSEIZEREF(NdbApiSignal* anApiSignal); + int receiveTCRELEASECONF(NdbApiSignal* anApiSignal); + int receiveTCRELEASEREF(NdbApiSignal* anApiSignal); + int receiveTC_COMMITCONF(const class TcCommitConf *); + int receiveTCKEYCONF(const class TcKeyConf *, Uint32 aDataLength); + int receiveTCKEY_FAILCONF(const class TcKeyFailConf *); + int receiveTCKEY_FAILREF(NdbApiSignal* anApiSignal); + int receiveTC_COMMITREF(NdbApiSignal* anApiSignal); + int receiveTCROLLBACKCONF(NdbApiSignal* anApiSignal); // Rec TCPREPARECONF ? + int receiveTCROLLBACKREF(NdbApiSignal* anApiSignal); // Rec TCPREPAREREF ? + int receiveTCROLLBACKREP(NdbApiSignal* anApiSignal); + int receiveTCINDXCONF(const class TcIndxConf *, Uint32 aDataLength); + int receiveTCINDXREF(NdbApiSignal*); + int receiveSCAN_TABREF(NdbApiSignal*); + int receiveSCAN_TABCONF(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(Uint8 abortoption, bool setFailure = true); + int OpCompleteSuccess(); + void CompletedOperations(); // Move active ops to list of completed + + 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 releaseScanOperations(NdbIndexScanOperation*); + bool releaseScanOperation(NdbIndexScanOperation** listhead, + NdbIndexScanOperation** listtail, + NdbIndexScanOperation* op); + void releaseExecutedScanOperation(NdbIndexScanOperation*); + + // 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 + 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); + + 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 theNoOfOpFetched; // How many operations was actually fetched + Uint32 theMyRef; // Our block reference + Uint32 theTCConPtr; // Transaction Co-ordinator connection pointer. + Uint64 theTransactionId; // theTransactionId of the transaction + Uint32 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 + + 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; + Uint8 m_abortOption; // Type of commi + + 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[2]; + Uint32 m_failed_db_nodes[2]; + + int report_node_failure(Uint32 id); + + // Scan operations + bool m_waitForReply; + NdbIndexScanOperation* m_theFirstScanOperation; + NdbIndexScanOperation* m_theLastScanOperation; + + NdbIndexScanOperation* m_firstExecutedScanOp; + + // Scan operations + // The operation actually performing the scan + NdbScanOperation* theScanningOp; + Uint32 theBuddyConPtr; + // optim: any blobs + bool theBlobFlag; + Uint8 thePendingBlobOps; + inline bool hasBlobOperation() { return theBlobFlag; } + + static void sendTC_COMMIT_ACK(class TransporterFacade *, NdbApiSignal *, + Uint32 transId1, Uint32 transId2, + Uint32 aBlockRef); + + void completedFail(const char * s); +#ifdef VM_TRACE + void printState(); +#endif + bool checkState_TransId(const Uint32 * transId) const; + + void remove_list(NdbOperation*& head, NdbOperation*); + void define_scan_op(NdbIndexScanOperation*); + + friend class HugoOperations; + friend struct Ndb_free_list_t<NdbTransaction>; +}; + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + +inline +Uint32 +NdbTransaction::get_send_size() +{ + return 0; +} + +inline +void +NdbTransaction::set_send_size(Uint32 send_size) +{ + return; +} + +#ifdef NDB_NO_DROPPED_SIGNAL +#include <stdlib.h> +#endif + +inline +int +NdbTransaction::checkMagicNumber() +{ + if (theMagicNumber == 0x37412619) + return 0; + else { +#ifdef NDB_NO_DROPPED_SIGNAL + abort(); +#endif + return -1; + } +} + +inline +bool +NdbTransaction::checkState_TransId(const Uint32 * transId) const { + const Uint32 tTmp1 = transId[0]; + const Uint32 tTmp2 = transId[1]; + Uint64 tRecTransId = (Uint64)tTmp1 + ((Uint64)tTmp2 << 32); + bool b = theStatus == Connected && theTransactionId == 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(); + +inline +void +NdbTransaction::setBuddyConPtr(Uint32 aBuddyConPtr) +{ + theBuddyConPtr = aBuddyConPtr; +} + +inline +Uint32 NdbTransaction::getBuddyConPtr() +{ + return theBuddyConPtr; +} + +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 setGCI(); + +Remark: Set global checkpoint identity of the transaction +******************************************************************************/ +inline +void +NdbTransaction::setGCI(int aGlobalCheckpointId) +{ + theGlobalCheckpointId = aGlobalCheckpointId; +} + +/****************************************************************************** +void OpSent(); + +Remark: An operation was sent with success that expects a response. +******************************************************************************/ +inline +void +NdbTransaction::OpSent() +{ + theNoOfOpSent++; +} + +/****************************************************************************** +void executePendingBlobOps(); +******************************************************************************/ +#include <stdlib.h> +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 diff --git a/storage/ndb/include/ndbapi/ndb_cluster_connection.hpp b/storage/ndb/include/ndbapi/ndb_cluster_connection.hpp new file mode 100644 index 00000000000..bc8993c4000 --- /dev/null +++ b/storage/ndb/include/ndbapi/ndb_cluster_connection.hpp @@ -0,0 +1,130 @@ +/* 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 */ + + +#ifndef CLUSTER_CONNECTION_HPP +#define CLUSTER_CONNECTION_HPP +#include <ndb_types.h> + +class Ndb_cluster_connection_node_iter +{ + friend class Ndb_cluster_connection_impl; +public: + Ndb_cluster_connection_node_iter() : scan_state(~0), + init_pos(0), + cur_pos(0) {}; +private: + unsigned char scan_state; + unsigned char init_pos; + unsigned char cur_pos; +}; + +/** + * @class Ndb_cluster_connection + * @brief Represents a connection to a cluster of storage nodes. + * + * Any NDB application program should begin with the creation of a + * single Ndb_cluster_connection object, and should make use of one + * and only one Ndb_cluster_connection. The application connects to + * a cluster management server when this object's connect() method is called. + * By using the wait_until_ready() method it is possible to wait + * for the connection to reach one or more storage nodes. + */ +class Ndb_cluster_connection { +public: + /** + * Create a connection to a cluster of storage nodes + * + * @param connectstring The connectstring for where to find the + * management server + */ + Ndb_cluster_connection(const char * connectstring = 0); + ~Ndb_cluster_connection(); + + /** + * Set a name on the connection, which will be reported in cluster log + * + * @param name + * + */ + void set_name(const char *name); + + /** + * Connect to a cluster management server + * + * @param no_retries specifies the number of retries to attempt + * in the event of connection failure; a negative value + * will result in the attempt to connect being repeated + * indefinitely + * + * @param retry_delay_in_seconds specifies how often retries should + * be performed + * + * @param verbose specifies if the method should print a report of its progess + * + * @return 0 = success, + * 1 = recoverable error, + * -1 = non-recoverable error + */ + int connect(int no_retries=0, int retry_delay_in_seconds=1, int verbose=0); + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + int start_connect_thread(int (*connect_callback)(void)= 0); +#endif + + /** + * Wait until the requested connection with one or more storage nodes is successful + * + * @param timeout_for_first_alive Number of seconds to wait until + * first live node is detected + * @param timeout_after_first_alive Number of seconds to wait after + * first live node is detected + * + * @return = 0 all nodes live, + * > 0 at least one node live, + * < 0 error + */ + int wait_until_ready(int timeout_for_first_alive, + int timeout_after_first_alive); + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + int get_no_ready(); + const char *get_connectstring(char *buf, int buf_sz) const; + int get_connected_port() const; + const char *get_connected_host() const; + + void set_optimized_node_selection(int val); + + unsigned no_db_nodes(); + unsigned node_id(); + unsigned get_connect_count() const; + + void init_get_next_node(Ndb_cluster_connection_node_iter &iter); + unsigned int get_next_node(Ndb_cluster_connection_node_iter &iter); + unsigned get_active_ndb_objects() const; + + Uint64 *get_latest_trans_gci(); +#endif + +private: + friend class Ndb; + friend class NdbImpl; + friend class Ndb_cluster_connection_impl; + class Ndb_cluster_connection_impl & m_impl; + Ndb_cluster_connection(Ndb_cluster_connection_impl&); +}; + +#endif diff --git a/storage/ndb/include/ndbapi/ndb_opt_defaults.h b/storage/ndb/include/ndbapi/ndb_opt_defaults.h new file mode 100644 index 00000000000..d03a9dcc36f --- /dev/null +++ b/storage/ndb/include/ndbapi/ndb_opt_defaults.h @@ -0,0 +1,23 @@ +/* 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 */ + +#ifndef NDB_OPT_DEFAULTS_H +#define NDB_OPT_DEFAULTS_H + +#define OPT_NDB_SHM_SIGNUM_DEFAULT 0 +#define OPT_NDB_SHM_DEFAULT 0 + +#endif diff --git a/storage/ndb/include/ndbapi/ndbapi_limits.h b/storage/ndb/include/ndbapi/ndbapi_limits.h new file mode 100644 index 00000000000..5c4db71b747 --- /dev/null +++ b/storage/ndb/include/ndbapi/ndbapi_limits.h @@ -0,0 +1,30 @@ +/* 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 */ + +#ifndef NDBAPI_LIMITS_H +#define NDBAPI_LIMITS_H + +#define NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY 32 +#define NDB_MAX_ATTRIBUTES_IN_INDEX NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY +#define NDB_MAX_ATTRIBUTES_IN_TABLE 128 + +#define NDB_MAX_TUPLE_SIZE_IN_WORDS 2013 +#define NDB_MAX_KEYSIZE_IN_WORDS 1023 +#define NDB_MAX_KEY_SIZE (NDB_MAX_KEYSIZE_IN_WORDS*4) +#define NDB_MAX_TUPLE_SIZE (NDB_MAX_TUPLE_SIZE_IN_WORDS*4) +#define NDB_MAX_ACTIVE_EVENTS 100 + +#endif diff --git a/storage/ndb/include/ndbapi/ndberror.h b/storage/ndb/include/ndbapi/ndberror.h new file mode 100644 index 00000000000..009818f5f4f --- /dev/null +++ b/storage/ndb/include/ndbapi/ndberror.h @@ -0,0 +1,110 @@ +/* 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 */ + +#ifndef NDBERROR_H +#define NDBERROR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + +typedef enum +{ + ndberror_st_success = 0, + ndberror_st_temporary = 1, + ndberror_st_permanent = 2, + ndberror_st_unknown = 3 +} ndberror_status_enum; + +typedef enum +{ + ndberror_cl_none = 0, + ndberror_cl_application = 1, + ndberror_cl_no_data_found = 2, + ndberror_cl_constraint_violation = 3, + ndberror_cl_schema_error = 4, + ndberror_cl_user_defined = 5, + ndberror_cl_insufficient_space = 6, + ndberror_cl_temporary_resource = 7, + ndberror_cl_node_recovery = 8, + ndberror_cl_overload = 9, + ndberror_cl_timeout_expired = 10, + ndberror_cl_unknown_result = 11, + ndberror_cl_internal_error = 12, + ndberror_cl_function_not_implemented = 13, + ndberror_cl_unknown_error_code = 14, + ndberror_cl_node_shutdown = 15, + ndberror_cl_configuration = 16, + ndberror_cl_schema_object_already_exists = 17, + ndberror_cl_internal_temporary = 18 +} ndberror_classification_enum; + + +typedef struct { + + /** + * Error status. + */ + ndberror_status_enum status; + + /** + * Error type + */ + ndberror_classification_enum classification; + + /** + * Error code + */ + int code; + + /** + * Mysql error code + */ + int mysql_code; + + /** + * Error message + */ + const char * message; + + /** + * The detailed description. This is extra information regarding the + * error which is not included in the error message. + * + * @note Is NULL when no details specified + */ + char * details; + +} ndberror_struct; + + +typedef ndberror_status_enum ndberror_status; +typedef ndberror_classification_enum ndberror_classification; + +const char *ndberror_status_message(ndberror_status); +const char *ndberror_classification_message(ndberror_classification); +void ndberror_update(ndberror_struct *); +int ndb_error_string(int err_no, char *str, int size); + +#endif /* doxygen skip internal*/ + +#ifdef __cplusplus +} +#endif + +#endif |