summaryrefslogtreecommitdiff
path: root/storage/ndb/ndbapi-examples
diff options
context:
space:
mode:
Diffstat (limited to 'storage/ndb/ndbapi-examples')
-rw-r--r--storage/ndb/ndbapi-examples/Makefile25
-rw-r--r--storage/ndb/ndbapi-examples/mgmapi_logevent_example/Makefile23
-rw-r--r--storage/ndb/ndbapi-examples/mgmapi_logevent_example/mgmapi_logevent.cpp140
-rw-r--r--storage/ndb/ndbapi-examples/ndbapi_async_example/Makefile23
-rw-r--r--storage/ndb/ndbapi-examples/ndbapi_async_example/ndbapi_async.cpp476
-rw-r--r--storage/ndb/ndbapi-examples/ndbapi_async_example/readme.txt3
-rw-r--r--storage/ndb/ndbapi-examples/ndbapi_async_example1/Makefile21
-rw-r--r--storage/ndb/ndbapi-examples/ndbapi_async_example1/ndbapi_async1.cpp144
-rw-r--r--storage/ndb/ndbapi-examples/ndbapi_event_example/Makefile23
-rw-r--r--storage/ndb/ndbapi-examples/ndbapi_event_example/ndbapi_event.cpp269
-rw-r--r--storage/ndb/ndbapi-examples/ndbapi_retries_example/Makefile21
-rw-r--r--storage/ndb/ndbapi-examples/ndbapi_retries_example/ndbapi_retries.cpp236
-rw-r--r--storage/ndb/ndbapi-examples/ndbapi_scan_example/Makefile23
-rw-r--r--storage/ndb/ndbapi-examples/ndbapi_scan_example/ndbapi_scan.cpp825
-rw-r--r--storage/ndb/ndbapi-examples/ndbapi_scan_example/readme.txt3
-rw-r--r--storage/ndb/ndbapi-examples/ndbapi_simple_example/Makefile23
-rw-r--r--storage/ndb/ndbapi-examples/ndbapi_simple_example/ndbapi_simple.cpp278
-rw-r--r--storage/ndb/ndbapi-examples/ndbapi_simple_index_example/Makefile23
-rw-r--r--storage/ndb/ndbapi-examples/ndbapi_simple_index_example/ndbapi_simple_index.cpp254
19 files changed, 2833 insertions, 0 deletions
diff --git a/storage/ndb/ndbapi-examples/Makefile b/storage/ndb/ndbapi-examples/Makefile
new file mode 100644
index 00000000000..965dc3ec29f
--- /dev/null
+++ b/storage/ndb/ndbapi-examples/Makefile
@@ -0,0 +1,25 @@
+BIN_DIRS := ndbapi_simple_example \
+ ndbapi_async_example \
+ ndbapi_async_example1 \
+ ndbapi_retries_example \
+ ndbapi_simple_index_example \
+ ndbapi_event_example \
+ ndbapi_scan_example \
+ mgmapi_logevent_example
+
+bins: $(patsubst %, _bins_%, $(BIN_DIRS))
+
+$(patsubst %, _bins_%, $(BIN_DIRS)) :
+ $(MAKE) -C $(patsubst _bins_%, %, $@) $(OPTS)
+
+libs:
+
+clean:
+ for f in ${BIN_DIRS}; do \
+ $(MAKE) -C $$f $@;\
+ done
+
+clean_dep: clean
+cleanall: clean
+tidy: clean
+distclean: clean
diff --git a/storage/ndb/ndbapi-examples/mgmapi_logevent_example/Makefile b/storage/ndb/ndbapi-examples/mgmapi_logevent_example/Makefile
new file mode 100644
index 00000000000..c1ca32dfe17
--- /dev/null
+++ b/storage/ndb/ndbapi-examples/mgmapi_logevent_example/Makefile
@@ -0,0 +1,23 @@
+TARGET = mgmapi_logevent
+SRCS = $(TARGET).cpp
+OBJS = $(TARGET).o
+CXX = g++
+CFLAGS = -c -Wall -fno-rtti -fno-exceptions
+CXXFLAGS =
+DEBUG =
+LFLAGS = -Wall
+TOP_SRCDIR = ../../..
+INCLUDE_DIR = $(TOP_SRCDIR)
+LIB_DIR = -L$(TOP_SRCDIR)/ndb/src/.libs \
+ -L$(TOP_SRCDIR)/libmysql_r/.libs \
+ -L$(TOP_SRCDIR)/mysys
+SYS_LIB =
+
+$(TARGET): $(OBJS)
+ $(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lz $(SYS_LIB) -o $(TARGET)
+
+$(TARGET).o: $(SRCS)
+ $(CXX) $(CFLAGS) -I$(INCLUDE_DIR)/include -I$(INCLUDE_DIR)/ndb/include -I$(INCLUDE_DIR)/ndb/include/mgmapi -I$(INCLUDE_DIR)/ndb/include/ndbapi $(SRCS)
+
+clean:
+ rm -f *.o $(TARGET)
diff --git a/storage/ndb/ndbapi-examples/mgmapi_logevent_example/mgmapi_logevent.cpp b/storage/ndb/ndbapi-examples/mgmapi_logevent_example/mgmapi_logevent.cpp
new file mode 100644
index 00000000000..5ec1fba6314
--- /dev/null
+++ b/storage/ndb/ndbapi-examples/mgmapi_logevent_example/mgmapi_logevent.cpp
@@ -0,0 +1,140 @@
+/* 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 */
+
+#include <mysql.h>
+#include <ndbapi/NdbApi.hpp>
+#include <mgmapi.h>
+#include <stdio.h>
+
+/*
+ * export LD_LIBRARY_PATH=../../../libmysql_r/.libs:../../../ndb/src/.libs
+ */
+
+#define MGMERROR(h) \
+{ \
+ fprintf(stderr, "code: %d msg: %s\n", \
+ ndb_mgm_get_latest_error(h), \
+ ndb_mgm_get_latest_error_msg(h)); \
+ exit(-1); \
+}
+
+#define LOGEVENTERROR(h) \
+{ \
+ fprintf(stderr, "code: %d msg: %s\n", \
+ ndb_logevent_get_latest_error(h), \
+ ndb_logevent_get_latest_error_msg(h)); \
+ exit(-1); \
+}
+
+int main()
+{
+ NdbMgmHandle h;
+ NdbLogEventHandle le;
+ int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_BACKUP,
+ 15, NDB_MGM_EVENT_CATEGORY_CONNECTION,
+ 15, NDB_MGM_EVENT_CATEGORY_NODE_RESTART,
+ 15, NDB_MGM_EVENT_CATEGORY_STARTUP,
+ 15, NDB_MGM_EVENT_CATEGORY_ERROR,
+ 0 };
+ struct ndb_logevent event;
+
+ ndb_init();
+
+ h= ndb_mgm_create_handle();
+ if ( h == 0)
+ {
+ printf("Unable to create handle\n");
+ exit(-1);
+ }
+ if (ndb_mgm_connect(h,0,0,0)) MGMERROR(h);
+
+ le= ndb_mgm_create_logevent_handle(h, filter);
+ if ( le == 0 ) MGMERROR(h);
+
+ while (1)
+ {
+ int timeout= 5000;
+ int r= ndb_logevent_get_next(le,&event,timeout);
+ if (r == 0)
+ printf("No event within %d milliseconds\n", timeout);
+ else if (r < 0)
+ LOGEVENTERROR(le)
+ else
+ {
+ switch (event.type) {
+ case NDB_LE_BackupStarted:
+ printf("Node %d: BackupStarted\n", event.source_nodeid);
+ printf(" Starting node ID: %d\n", event.BackupStarted.starting_node);
+ printf(" Backup ID: %d\n", event.BackupStarted.backup_id);
+ break;
+ case NDB_LE_BackupCompleted:
+ printf("Node %d: BackupCompleted\n", event.source_nodeid);
+ printf(" Backup ID: %d\n", event.BackupStarted.backup_id);
+ break;
+ case NDB_LE_BackupAborted:
+ printf("Node %d: BackupAborted\n", event.source_nodeid);
+ break;
+ case NDB_LE_BackupFailedToStart:
+ printf("Node %d: BackupFailedToStart\n", event.source_nodeid);
+ break;
+
+ case NDB_LE_NodeFailCompleted:
+ printf("Node %d: NodeFailCompleted\n", event.source_nodeid);
+ break;
+ case NDB_LE_ArbitResult:
+ printf("Node %d: ArbitResult\n", event.source_nodeid);
+ printf(" code %d, arbit_node %d\n",
+ event.ArbitResult.code & 0xffff,
+ event.ArbitResult.arbit_node);
+ break;
+ case NDB_LE_DeadDueToHeartbeat:
+ printf("Node %d: DeadDueToHeartbeat\n", event.source_nodeid);
+ printf(" node %d\n", event.DeadDueToHeartbeat.node);
+ break;
+
+ case NDB_LE_Connected:
+ printf("Node %d: Connected\n", event.source_nodeid);
+ printf(" node %d\n", event.Connected.node);
+ break;
+ case NDB_LE_Disconnected:
+ printf("Node %d: Disconnected\n", event.source_nodeid);
+ printf(" node %d\n", event.Disconnected.node);
+ break;
+ case NDB_LE_NDBStartCompleted:
+ printf("Node %d: StartCompleted\n", event.source_nodeid);
+ printf(" version %d.%d.%d\n",
+ event.NDBStartCompleted.version >> 16 & 0xff,
+ event.NDBStartCompleted.version >> 8 & 0xff,
+ event.NDBStartCompleted.version >> 0 & 0xff);
+ break;
+ case NDB_LE_ArbitState:
+ printf("Node %d: ArbitState\n", event.source_nodeid);
+ printf(" code %d, arbit_node %d\n",
+ event.ArbitState.code & 0xffff,
+ event.ArbitResult.arbit_node);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ ndb_mgm_destroy_logevent_handle(&le);
+ ndb_mgm_destroy_handle(&h);
+ ndb_end(0);
+ return 0;
+}
diff --git a/storage/ndb/ndbapi-examples/ndbapi_async_example/Makefile b/storage/ndb/ndbapi-examples/ndbapi_async_example/Makefile
new file mode 100644
index 00000000000..55e4a13343f
--- /dev/null
+++ b/storage/ndb/ndbapi-examples/ndbapi_async_example/Makefile
@@ -0,0 +1,23 @@
+TARGET = ndbapi_async
+SRCS = $(TARGET).cpp
+OBJS = $(TARGET).o
+CXX = g++
+CFLAGS = -g -c -Wall -fno-rtti -fno-exceptions
+CXXFLAGS = -g
+DEBUG =
+LFLAGS = -Wall
+TOP_SRCDIR = ../../..
+INCLUDE_DIR = $(TOP_SRCDIR)
+LIB_DIR = -L$(TOP_SRCDIR)/ndb/src/.libs \
+ -L$(TOP_SRCDIR)/libmysql_r/.libs \
+ -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+SYS_LIB =
+
+$(TARGET): $(OBJS)
+ $(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+
+$(TARGET).o: $(SRCS)
+ $(CXX) $(CFLAGS) -I$(INCLUDE_DIR)/include -I$(INCLUDE_DIR)/extra -I$(INCLUDE_DIR)/ndb/include -I$(INCLUDE_DIR)/ndb/include/ndbapi $(SRCS)
+
+clean:
+ rm -f *.o $(TARGET)
diff --git a/storage/ndb/ndbapi-examples/ndbapi_async_example/ndbapi_async.cpp b/storage/ndb/ndbapi-examples/ndbapi_async_example/ndbapi_async.cpp
new file mode 100644
index 00000000000..aa745f4d28d
--- /dev/null
+++ b/storage/ndb/ndbapi-examples/ndbapi_async_example/ndbapi_async.cpp
@@ -0,0 +1,476 @@
+
+
+/* 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 */
+
+
+/**
+ * ndbapi_async.cpp:
+ * Illustrates how to use callbacks and error handling using the asynchronous
+ * part of the NDBAPI.
+ *
+ * Classes and methods in NDBAPI used in this example:
+ *
+ * Ndb_cluster_connection
+ * connect()
+ * wait_until_ready()
+ *
+ * Ndb
+ * init()
+ * startTransaction()
+ * closeTransaction()
+ * sendPollNdb()
+ * getNdbError()
+ *
+ * NdbConnection
+ * getNdbOperation()
+ * executeAsynchPrepare()
+ * getNdbError()
+ *
+ * NdbOperation
+ * insertTuple()
+ * equal()
+ * setValue()
+ *
+ */
+
+
+#include <mysql.h>
+#include <mysqld_error.h>
+#include <NdbApi.hpp>
+
+#include <iostream> // Used for cout
+
+/**
+ * Helper sleep function
+ */
+static void
+milliSleep(int milliseconds){
+ struct timeval sleeptime;
+ sleeptime.tv_sec = milliseconds / 1000;
+ sleeptime.tv_usec = (milliseconds - (sleeptime.tv_sec * 1000)) * 1000000;
+ select(0, 0, 0, 0, &sleeptime);
+}
+
+
+/**
+ * error printout macro
+ */
+#define PRINT_ERROR(code,msg) \
+ std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
+ << ", code: " << code \
+ << ", msg: " << msg << "." << std::endl
+#define MYSQLERROR(mysql) { \
+ PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
+ exit(-1); }
+#define APIERROR(error) { \
+ PRINT_ERROR(error.code,error.message); \
+ exit(-1); }
+
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+/**
+ * callback struct.
+ * transaction : index of the transaction in transaction[] array below
+ * data : the data that the transaction was modifying.
+ * retries : counter for how many times the trans. has been retried
+ */
+typedef struct {
+ Ndb * ndb;
+ int transaction;
+ int data;
+ int retries;
+} async_callback_t;
+
+/**
+ * Structure used in "free list" to a NdbTransaction
+ */
+typedef struct {
+ NdbTransaction* conn;
+ int used;
+} transaction_t;
+
+/**
+ * Free list holding transactions
+ */
+transaction_t transaction[1024]; //1024 - max number of outstanding
+ //transaction in one Ndb object
+
+#endif
+/**
+ * prototypes
+ */
+
+/**
+ * Prepare and send transaction
+ */
+int populate(Ndb * myNdb, int data, async_callback_t * cbData);
+
+/**
+ * Error handler.
+ */
+bool asynchErrorHandler(NdbTransaction * trans, Ndb* ndb);
+
+/**
+ * Exit function
+ */
+void asynchExitHandler(Ndb * m_ndb) ;
+
+/**
+ * Helper function used in callback(...)
+ */
+void closeTransaction(Ndb * ndb , async_callback_t * cb);
+
+/**
+ * Function to create table
+ */
+int create_table(Ndb * myNdb);
+
+/**
+ * stat. variables
+ */
+int tempErrors = 0;
+int permErrors = 0;
+
+void
+closeTransaction(Ndb * ndb , async_callback_t * cb)
+{
+ ndb->closeTransaction(transaction[cb->transaction].conn);
+ transaction[cb->transaction].conn = 0;
+ transaction[cb->transaction].used = 0;
+ cb->retries++;
+}
+
+/**
+ * Callback executed when transaction has return from NDB
+ */
+static void
+callback(int result, NdbTransaction* trans, void* aObject)
+{
+ async_callback_t * cbData = (async_callback_t *)aObject;
+ if (result<0)
+ {
+ /**
+ * Error: Temporary or permanent?
+ */
+ if (asynchErrorHandler(trans, (Ndb*)cbData->ndb))
+ {
+ closeTransaction((Ndb*)cbData->ndb, cbData);
+ while(populate((Ndb*)cbData->ndb, cbData->data, cbData) < 0)
+ milliSleep(10);
+ }
+ else
+ {
+ std::cout << "Restore: Failed to restore data "
+ << "due to a unrecoverable error. Exiting..." << std::endl;
+ delete cbData;
+ asynchExitHandler((Ndb*)cbData->ndb);
+ }
+ }
+ else
+ {
+ /**
+ * OK! close transaction
+ */
+ closeTransaction((Ndb*)cbData->ndb, cbData);
+ delete cbData;
+ }
+}
+
+
+/**
+ * Create table "GARAGE"
+ */
+int create_table(MYSQL &mysql)
+{
+ while (mysql_query(&mysql,
+ "CREATE TABLE"
+ " GARAGE"
+ " (REG_NO INT UNSIGNED NOT NULL,"
+ " BRAND CHAR(20) NOT NULL,"
+ " COLOR CHAR(20) NOT NULL,"
+ " PRIMARY KEY USING HASH (REG_NO))"
+ " ENGINE=NDB"))
+ {
+ if (mysql_errno(&mysql) != ER_TABLE_EXISTS_ERROR)
+ MYSQLERROR(mysql);
+ std::cout << "MySQL Cluster already has example table: GARAGE. "
+ << "Dropping it..." << std::endl;
+ /**************
+ * Drop table *
+ **************/
+ if (mysql_query(&mysql, "DROP TABLE GARAGE"))
+ MYSQLERROR(mysql);
+ }
+ return 1;
+}
+
+void asynchExitHandler(Ndb * m_ndb)
+{
+ if (m_ndb != NULL)
+ delete m_ndb;
+ exit(-1);
+}
+
+/* returns true if is recoverable (temporary),
+ * false if it is an error that is permanent.
+ */
+bool asynchErrorHandler(NdbTransaction * trans, Ndb* ndb)
+{
+ NdbError error = trans->getNdbError();
+ switch(error.status)
+ {
+ case NdbError::Success:
+ return false;
+ break;
+
+ case NdbError::TemporaryError:
+ /**
+ * The error code indicates a temporary error.
+ * The application should typically retry.
+ * (Includes classifications: NdbError::InsufficientSpace,
+ * NdbError::TemporaryResourceError, NdbError::NodeRecoveryError,
+ * NdbError::OverloadError, NdbError::NodeShutdown
+ * and NdbError::TimeoutExpired.)
+ *
+ * We should sleep for a while and retry, except for insufficient space
+ */
+ if(error.classification == NdbError::InsufficientSpace)
+ return false;
+ milliSleep(10);
+ tempErrors++;
+ return true;
+ break;
+ case NdbError::UnknownResult:
+ std::cout << error.message << std::endl;
+ return false;
+ break;
+ default:
+ case NdbError::PermanentError:
+ switch (error.code)
+ {
+ case 499:
+ case 250:
+ milliSleep(10);
+ return true; // SCAN errors that can be retried. Requires restart of scan.
+ default:
+ break;
+ }
+ //ERROR
+ std::cout << error.message << std::endl;
+ return false;
+ break;
+ }
+ return false;
+}
+
+static int nPreparedTransactions = 0;
+static int MAX_RETRIES = 10;
+static int parallelism = 100;
+
+
+/************************************************************************
+ * populate()
+ * 1. Prepare 'parallelism' number of insert transactions.
+ * 2. Send transactions to NDB and wait for callbacks to execute
+ */
+int populate(Ndb * myNdb, int data, async_callback_t * cbData)
+{
+
+ NdbOperation* myNdbOperation; // For operations
+ const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("GARAGE");
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
+
+ async_callback_t * cb;
+ int retries = 0;
+ int current = 0;
+ for(int i=0; i<1024; i++)
+ {
+ if(transaction[i].used == 0)
+ {
+ current = i;
+ if (cbData == 0)
+ {
+ /**
+ * We already have a callback
+ * This is an absolutely new transaction
+ */
+ cb = new async_callback_t;
+ cb->retries = 0;
+ }
+ else
+ {
+ /**
+ * We already have a callback
+ */
+ cb =cbData;
+ retries = cbData->retries;
+ }
+ /**
+ * Set data used by the callback
+ */
+ cb->ndb = myNdb; //handle to Ndb object so that we can close transaction
+ // in the callback (alt. make myNdb global).
+
+ cb->data = data; //this is the data we want to insert
+ cb->transaction = current; //This is the number (id) of this transaction
+ transaction[current].used = 1 ; //Mark the transaction as used
+ break;
+ }
+ }
+ if(!current)
+ return -1;
+
+ while(retries < MAX_RETRIES)
+ {
+ transaction[current].conn = myNdb->startTransaction();
+ if (transaction[current].conn == NULL) {
+ if (asynchErrorHandler(transaction[current].conn, myNdb))
+ {
+ /**
+ * no transaction to close since conn == null
+ */
+ milliSleep(10);
+ retries++;
+ continue;
+ }
+ asynchExitHandler(myNdb);
+ }
+ myNdbOperation = transaction[current].conn->getNdbOperation(myTable);
+ if (myNdbOperation == NULL)
+ {
+ if (asynchErrorHandler(transaction[current].conn, myNdb))
+ {
+ myNdb->closeTransaction(transaction[current].conn);
+ transaction[current].conn = 0;
+ milliSleep(10);
+ retries++;
+ continue;
+ }
+ asynchExitHandler(myNdb);
+ } // if
+ if(myNdbOperation->insertTuple() < 0 ||
+ myNdbOperation->equal("REG_NO", data) < 0 ||
+ myNdbOperation->setValue("BRAND", "Mercedes") <0 ||
+ myNdbOperation->setValue("COLOR", "Blue") < 0)
+ {
+ if (asynchErrorHandler(transaction[current].conn, myNdb))
+ {
+ myNdb->closeTransaction(transaction[current].conn);
+ transaction[current].conn = 0;
+ retries++;
+ milliSleep(10);
+ continue;
+ }
+ asynchExitHandler(myNdb);
+ }
+
+ /*Prepare transaction (the transaction is NOT yet sent to NDB)*/
+ transaction[current].conn->executeAsynchPrepare(NdbTransaction::Commit,
+ &callback,
+ cb);
+ /**
+ * When we have prepared parallelism number of transactions ->
+ * send the transaction to ndb.
+ * Next time we will deal with the transactions are in the
+ * callback. There we will see which ones that were successful
+ * and which ones to retry.
+ */
+ if (nPreparedTransactions == parallelism-1)
+ {
+ // send-poll all transactions
+ // close transaction is done in callback
+ myNdb->sendPollNdb(3000, parallelism );
+ nPreparedTransactions=0;
+ }
+ else
+ nPreparedTransactions++;
+ return 1;
+ }
+ std::cout << "Unable to recover from errors. Exiting..." << std::endl;
+ asynchExitHandler(myNdb);
+ return -1;
+}
+
+int main()
+{
+ ndb_init();
+ MYSQL mysql;
+
+ /**************************************************************
+ * Connect to mysql server and create table *
+ **************************************************************/
+ {
+ if ( !mysql_init(&mysql) ) {
+ std::cout << "mysql_init failed\n";
+ exit(-1);
+ }
+ if ( !mysql_real_connect(&mysql, "localhost", "root", "", "",
+ 3306, "/tmp/mysql.sock", 0) )
+ MYSQLERROR(mysql);
+
+ mysql_query(&mysql, "CREATE DATABASE TEST_DB");
+ if (mysql_query(&mysql, "USE TEST_DB") != 0) MYSQLERROR(mysql);
+
+ create_table(mysql);
+ }
+
+ /**************************************************************
+ * Connect to ndb cluster *
+ **************************************************************/
+ Ndb_cluster_connection cluster_connection;
+ if (cluster_connection.connect(4, 5, 1))
+ {
+ std::cout << "Unable to connect to cluster within 30 secs." << std::endl;
+ exit(-1);
+ }
+ // Optionally connect and wait for the storage nodes (ndbd's)
+ if (cluster_connection.wait_until_ready(30,0) < 0)
+ {
+ std::cout << "Cluster was not ready within 30 secs.\n";
+ exit(-1);
+ }
+
+ Ndb* myNdb = new Ndb( &cluster_connection,
+ "TEST_DB" ); // Object representing the database
+ if (myNdb->init(1024) == -1) { // Set max 1024 parallel transactions
+ APIERROR(myNdb->getNdbError());
+ }
+
+ /**
+ * Initialise transaction array
+ */
+ for(int i = 0 ; i < 1024 ; i++)
+ {
+ transaction[i].used = 0;
+ transaction[i].conn = 0;
+
+ }
+ int i=0;
+ /**
+ * Do 20000 insert transactions.
+ */
+ while(i < 20000)
+ {
+ while(populate(myNdb,i,0)<0) // <0, no space on free list. Sleep and try again.
+ milliSleep(10);
+
+ i++;
+ }
+ std::cout << "Number of temporary errors: " << tempErrors << std::endl;
+ delete myNdb;
+}
diff --git a/storage/ndb/ndbapi-examples/ndbapi_async_example/readme.txt b/storage/ndb/ndbapi-examples/ndbapi_async_example/readme.txt
new file mode 100644
index 00000000000..47cb4bf9ffa
--- /dev/null
+++ b/storage/ndb/ndbapi-examples/ndbapi_async_example/readme.txt
@@ -0,0 +1,3 @@
+1. Set NDB_OS in Makefile
+2. Add path to libNDB_API.so in LD_LIBRARY_PATH
+3. Set NDB_CONNECTSTRING
diff --git a/storage/ndb/ndbapi-examples/ndbapi_async_example1/Makefile b/storage/ndb/ndbapi-examples/ndbapi_async_example1/Makefile
new file mode 100644
index 00000000000..7f6ea0b4d25
--- /dev/null
+++ b/storage/ndb/ndbapi-examples/ndbapi_async_example1/Makefile
@@ -0,0 +1,21 @@
+TARGET = ndbapi_async1
+SRCS = ndbapi_async1.cpp
+OBJS = ndbapi_async1.o
+CXX = g++
+CFLAGS = -c -Wall -fno-rtti -fno-exceptions
+DEBUG =
+LFLAGS = -Wall
+INCLUDE_DIR = ../../include
+LIB_DIR = -L../../src/.libs \
+ -L../../../libmysql_r/.libs \
+ -L../../../mysys -L../../../strings
+SYS_LIB =
+
+$(TARGET): $(OBJS)
+ $(CXX) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+
+$(TARGET).o: $(SRCS)
+ $(CXX) $(CFLAGS) -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi $(SRCS)
+
+clean:
+ rm -f *.o $(TARGET)
diff --git a/storage/ndb/ndbapi-examples/ndbapi_async_example1/ndbapi_async1.cpp b/storage/ndb/ndbapi-examples/ndbapi_async_example1/ndbapi_async1.cpp
new file mode 100644
index 00000000000..e8bc19e267b
--- /dev/null
+++ b/storage/ndb/ndbapi-examples/ndbapi_async_example1/ndbapi_async1.cpp
@@ -0,0 +1,144 @@
+/* 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 */
+
+//
+// ndbapi_async1.cpp: Using asynchronous transactions in NDB API
+//
+// Execute ndbapi_example1 to create the table "MYTABLENAME"
+// before executing this program.
+//
+// Correct output from this program is:
+//
+// Successful insert.
+// Successful insert.
+
+#include <NdbApi.hpp>
+
+// Used for cout
+#include <iostream>
+
+#define APIERROR(error) \
+ { std::cout << "Error in " << __FILE__ << ", line:" << __LINE__ << ", code:" \
+ << error.code << ", msg: " << error.message << "." << std::endl; \
+ exit(-1); }
+
+static void callback(int result, NdbTransaction* NdbObject, void* aObject);
+
+int main()
+{
+ ndb_init();
+
+ Ndb_cluster_connection *cluster_connection=
+ new Ndb_cluster_connection(); // Object representing the cluster
+
+ if (cluster_connection->wait_until_ready(30,30))
+ {
+ std::cout << "Cluster was not ready within 30 secs." << std::endl;
+ exit(-1);
+ }
+
+ int r= cluster_connection->connect(5 /* retries */,
+ 3 /* delay between retries */,
+ 1 /* verbose */);
+ if (r > 0)
+ {
+ std::cout
+ << "Cluster connect failed, possibly resolved with more retries.\n";
+ exit(-1);
+ }
+ else if (r < 0)
+ {
+ std::cout
+ << "Cluster connect failed.\n";
+ exit(-1);
+ }
+
+ if (cluster_connection->wait_until_ready(30,30))
+ {
+ std::cout << "Cluster was not ready within 30 secs." << std::endl;
+ exit(-1);
+ }
+
+ Ndb* myNdb = new Ndb( cluster_connection,
+ "TEST_DB_2" ); // Object representing the database
+
+ NdbTransaction* myNdbTransaction[2]; // For transactions
+ NdbOperation* myNdbOperation; // For operations
+
+ if (myNdb->init(2) == -1) { // Want two parallel insert transactions
+ APIERROR(myNdb->getNdbError());
+ exit(-1);
+ }
+
+ /******************************************************
+ * Insert (we do two insert transactions in parallel) *
+ ******************************************************/
+ const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
+ for (int i = 0; i < 2; i++) {
+ myNdbTransaction[i] = myNdb->startTransaction();
+ if (myNdbTransaction[i] == NULL) APIERROR(myNdb->getNdbError());
+
+ myNdbOperation = myNdbTransaction[i]->getNdbOperation(myTable);
+ if (myNdbOperation == NULL) APIERROR(myNdbTransaction[i]->getNdbError());
+
+ myNdbOperation->insertTuple();
+ myNdbOperation->equal("ATTR1", 20 + i);
+ myNdbOperation->setValue("ATTR2", 20 + i);
+
+ // Prepare transaction (the transaction is NOT yet sent to NDB)
+ myNdbTransaction[i]->executeAsynchPrepare(NdbTransaction::Commit,
+ &callback, NULL);
+ }
+
+ // Send all transactions to NDB
+ myNdb->sendPreparedTransactions(0);
+
+ // Poll all transactions
+ myNdb->pollNdb(3000, 2);
+
+ // Close all transactions
+ for (int i = 0; i < 2; i++)
+ myNdb->closeTransaction(myNdbTransaction[i]);
+
+ delete myNdb;
+ delete cluster_connection;
+
+ ndb_end(0);
+ return 0;
+}
+
+/*
+ * callback : This is called when the transaction is polled
+ *
+ * (This function must have three arguments:
+ * - The result of the transaction,
+ * - The NdbTransaction object, and
+ * - A pointer to an arbitrary object.)
+ */
+
+static void
+callback(int result, NdbTransaction* myTrans, void* aObject)
+{
+ if (result == -1) {
+ std::cout << "Poll error: " << std::endl;
+ APIERROR(myTrans->getNdbError());
+ } else {
+ std::cout << "Successful insert." << std::endl;
+ }
+}
diff --git a/storage/ndb/ndbapi-examples/ndbapi_event_example/Makefile b/storage/ndb/ndbapi-examples/ndbapi_event_example/Makefile
new file mode 100644
index 00000000000..12e109c654f
--- /dev/null
+++ b/storage/ndb/ndbapi-examples/ndbapi_event_example/Makefile
@@ -0,0 +1,23 @@
+TARGET = ndbapi_event
+SRCS = ndbapi_event.cpp
+OBJS = ndbapi_event.o
+CXX = g++
+CFLAGS = -c -Wall -fno-rtti -fno-exceptions
+CXXFLAGS =
+DEBUG =
+LFLAGS = -Wall
+TOP_SRCDIR = ../../..
+INCLUDE_DIR = $(TOP_SRCDIR)/ndb/include
+LIB_DIR = -L$(TOP_SRCDIR)/ndb/src/.libs \
+ -L$(TOP_SRCDIR)/libmysql_r/.libs \
+ -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+SYS_LIB =
+
+$(TARGET): $(OBJS)
+ $(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+
+$(TARGET).o: $(SRCS)
+ $(CXX) $(CFLAGS) -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi $(SRCS)
+
+clean:
+ rm -f *.o $(TARGET)
diff --git a/storage/ndb/ndbapi-examples/ndbapi_event_example/ndbapi_event.cpp b/storage/ndb/ndbapi-examples/ndbapi_event_example/ndbapi_event.cpp
new file mode 100644
index 00000000000..286f6fafbab
--- /dev/null
+++ b/storage/ndb/ndbapi-examples/ndbapi_event_example/ndbapi_event.cpp
@@ -0,0 +1,269 @@
+/* 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 */
+
+/**
+ * ndbapi_event.cpp: Using API level events in NDB API
+ *
+ * Classes and methods used in this example:
+ *
+ * Ndb_cluster_connection
+ * connect()
+ * wait_until_ready()
+ *
+ * Ndb
+ * init()
+ * getDictionary()
+ * createEventOperation()
+ * dropEventOperation()
+ * pollEvents()
+ *
+ * NdbDictionary
+ * createEvent()
+ * dropEvent()
+ *
+ * NdbDictionary::Event
+ * setTable()
+ * addTableEvent()
+ * addEventColumn()
+ *
+ * NdbEventOperation
+ * getValue()
+ * getPreValue()
+ * execute()
+ * next()
+ * isConsistent()
+ * getEventType()
+ *
+ */
+
+#include <NdbApi.hpp>
+
+// Used for cout
+#include <stdio.h>
+#include <iostream>
+#include <unistd.h>
+
+
+/**
+ *
+ * Assume that there is a table TAB0 which is being updated by
+ * another process (e.g. flexBench -l 0 -stdtables).
+ * We want to monitor what happens with columns COL0, COL2, COL11
+ *
+ * or together with the mysql client;
+ *
+ * shell> mysql -u root
+ * mysql> create database TEST_DB;
+ * mysql> use TEST_DB;
+ * mysql> create table TAB0 (COL0 int primary key, COL1 int, COL11 int) engine=ndb;
+ *
+ * In another window start ndbapi_event, wait until properly started
+ *
+ insert into TAB0 values (1,2,3);
+ insert into TAB0 values (2,2,3);
+ insert into TAB0 values (3,2,9);
+ update TAB0 set COL1=10 where COL0=1;
+ delete from TAB0 where COL0=1;
+ *
+ * you should see the data popping up in the example window
+ *
+ */
+
+#define APIERROR(error) \
+ { std::cout << "Error in " << __FILE__ << ", line:" << __LINE__ << ", code:" \
+ << error.code << ", msg: " << error.message << "." << std::endl; \
+ exit(-1); }
+
+int myCreateEvent(Ndb* myNdb,
+ const char *eventName,
+ const char *eventTableName,
+ const char **eventColumnName,
+ const int noEventColumnName);
+
+int main()
+{
+ ndb_init();
+
+ Ndb_cluster_connection *cluster_connection=
+ new Ndb_cluster_connection(); // Object representing the cluster
+
+ int r= cluster_connection->connect(5 /* retries */,
+ 3 /* delay between retries */,
+ 1 /* verbose */);
+ if (r > 0)
+ {
+ std::cout
+ << "Cluster connect failed, possibly resolved with more retries.\n";
+ exit(-1);
+ }
+ else if (r < 0)
+ {
+ std::cout
+ << "Cluster connect failed.\n";
+ exit(-1);
+ }
+
+ if (cluster_connection->wait_until_ready(30,30))
+ {
+ std::cout << "Cluster was not ready within 30 secs." << std::endl;
+ exit(-1);
+ }
+
+ Ndb* myNdb= new Ndb(cluster_connection,
+ "TEST_DB"); // Object representing the database
+
+ if (myNdb->init() == -1) APIERROR(myNdb->getNdbError());
+
+ const char *eventName= "CHNG_IN_TAB0";
+ const char *eventTableName= "TAB0";
+ const int noEventColumnName= 3;
+ const char *eventColumnName[noEventColumnName]=
+ {"COL0",
+ "COL1",
+ "COL11"};
+
+ // Create events
+ myCreateEvent(myNdb,
+ eventName,
+ eventTableName,
+ eventColumnName,
+ noEventColumnName);
+
+ int j= 0;
+ while (j < 5) {
+
+ // Start "transaction" for handling events
+ NdbEventOperation* op;
+ printf("create EventOperation\n");
+ if ((op = myNdb->createEventOperation(eventName,100)) == NULL)
+ APIERROR(myNdb->getNdbError());
+
+ printf("get values\n");
+ NdbRecAttr* recAttr[noEventColumnName];
+ NdbRecAttr* recAttrPre[noEventColumnName];
+ // primary keys should always be a part of the result
+ for (int i = 0; i < noEventColumnName; i++) {
+ recAttr[i] = op->getValue(eventColumnName[i]);
+ recAttrPre[i] = op->getPreValue(eventColumnName[i]);
+ }
+
+ // set up the callbacks
+ printf("execute\n");
+ // This starts changes to "start flowing"
+ if (op->execute())
+ APIERROR(op->getNdbError());
+
+ int i= 0;
+ while(i < 40) {
+ // printf("now waiting for event...\n");
+ int r= myNdb->pollEvents(1000); // wait for event or 1000 ms
+ if (r > 0) {
+ // printf("got data! %d\n", r);
+ int overrun;
+ while (op->next(&overrun) > 0) {
+ i++;
+ if (!op->isConsistent())
+ printf("A node failure has occured and events might be missing\n");
+ switch (op->getEventType()) {
+ case NdbDictionary::Event::TE_INSERT:
+ printf("%u INSERT: ", i);
+ break;
+ case NdbDictionary::Event::TE_DELETE:
+ printf("%u DELETE: ", i);
+ break;
+ case NdbDictionary::Event::TE_UPDATE:
+ printf("%u UPDATE: ", i);
+ break;
+ default:
+ abort(); // should not happen
+ }
+ printf("overrun %u pk %u: ", overrun, recAttr[0]->u_32_value());
+ for (int i = 1; i < noEventColumnName; i++) {
+ if (recAttr[i]->isNULL() >= 0) { // we have a value
+ printf(" post[%u]=", i);
+ if (recAttr[i]->isNULL() == 0) // we have a non-null value
+ printf("%u", recAttr[i]->u_32_value());
+ else // we have a null value
+ printf("NULL");
+ }
+ if (recAttrPre[i]->isNULL() >= 0) { // we have a value
+ printf(" pre[%u]=", i);
+ if (recAttrPre[i]->isNULL() == 0) // we have a non-null value
+ printf("%u", recAttrPre[i]->u_32_value());
+ else // we have a null value
+ printf("NULL");
+ }
+ }
+ printf("\n");
+ }
+ } else
+ ;//printf("timed out\n");
+ }
+ // don't want to listen to events anymore
+ if (myNdb->dropEventOperation(op)) APIERROR(myNdb->getNdbError());
+
+ j++;
+ }
+
+ {
+ NdbDictionary::Dictionary *myDict = myNdb->getDictionary();
+ if (!myDict) APIERROR(myNdb->getNdbError());
+ // remove event from database
+ if (myDict->dropEvent(eventName)) APIERROR(myDict->getNdbError());
+ }
+
+ delete myNdb;
+ delete cluster_connection;
+ ndb_end(0);
+ return 0;
+}
+
+int myCreateEvent(Ndb* myNdb,
+ const char *eventName,
+ const char *eventTableName,
+ const char **eventColumnNames,
+ const int noEventColumnNames)
+{
+ NdbDictionary::Dictionary *myDict= myNdb->getDictionary();
+ if (!myDict) APIERROR(myNdb->getNdbError());
+
+ const NdbDictionary::Table *table= myDict->getTable(eventTableName);
+ if (!table) APIERROR(myDict->getNdbError());
+
+ NdbDictionary::Event myEvent(eventName, *table);
+ myEvent.addTableEvent(NdbDictionary::Event::TE_ALL);
+ // myEvent.addTableEvent(NdbDictionary::Event::TE_INSERT);
+ // myEvent.addTableEvent(NdbDictionary::Event::TE_UPDATE);
+ // myEvent.addTableEvent(NdbDictionary::Event::TE_DELETE);
+
+ myEvent.addEventColumns(noEventColumnNames, eventColumnNames);
+
+ // Add event to database
+ if (myDict->createEvent(myEvent) == 0)
+ myEvent.print();
+ else if (myDict->getNdbError().classification ==
+ NdbError::SchemaObjectExists) {
+ printf("Event creation failed, event exists\n");
+ printf("dropping Event...\n");
+ if (myDict->dropEvent(eventName)) APIERROR(myDict->getNdbError());
+ // try again
+ // Add event to database
+ if ( myDict->createEvent(myEvent)) APIERROR(myDict->getNdbError());
+ } else
+ APIERROR(myDict->getNdbError());
+
+ return 0;
+}
diff --git a/storage/ndb/ndbapi-examples/ndbapi_retries_example/Makefile b/storage/ndb/ndbapi-examples/ndbapi_retries_example/Makefile
new file mode 100644
index 00000000000..829a7009031
--- /dev/null
+++ b/storage/ndb/ndbapi-examples/ndbapi_retries_example/Makefile
@@ -0,0 +1,21 @@
+TARGET = ndbapi_retries
+SRCS = ndbapi_retries.cpp
+OBJS = ndbapi_retries.o
+CXX = g++
+CFLAGS = -c -Wall -fno-rtti -fno-exceptions
+DEBUG =
+LFLAGS = -Wall
+INCLUDE_DIR = ../../include
+LIB_DIR = -L../../src/.libs \
+ -L../../../libmysql_r/.libs \
+ -L../../../mysys -L../../../strings
+SYS_LIB =
+
+$(TARGET): $(OBJS)
+ $(CXX) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+
+$(TARGET).o: $(SRCS)
+ $(CXX) $(CFLAGS) -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi $(SRCS)
+
+clean:
+ rm -f *.o $(TARGET)
diff --git a/storage/ndb/ndbapi-examples/ndbapi_retries_example/ndbapi_retries.cpp b/storage/ndb/ndbapi-examples/ndbapi_retries_example/ndbapi_retries.cpp
new file mode 100644
index 00000000000..8c29fe31446
--- /dev/null
+++ b/storage/ndb/ndbapi-examples/ndbapi_retries_example/ndbapi_retries.cpp
@@ -0,0 +1,236 @@
+/* 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 */
+
+//
+// ndbapi_retries.cpp: Error handling and transaction retries
+//
+// Execute ndbapi_simple to create the table "MYTABLENAME"
+// before executing this program.
+//
+// There are many ways to program using the NDB API. In this example
+// we execute two inserts in the same transaction using
+// NdbConnection::execute(NoCommit).
+//
+// Transaction failing is handled by re-executing the transaction
+// in case of non-permanent transaction errors.
+// Application errors (i.e. errors at points marked with APIERROR)
+// should be handled by the application programmer.
+
+#include <NdbApi.hpp>
+
+// Used for cout
+#include <iostream>
+
+// Used for sleep (use your own version of sleep)
+#include <unistd.h>
+#define TIME_TO_SLEEP_BETWEEN_TRANSACTION_RETRIES 1
+
+//
+// APIERROR prints an NdbError object
+//
+#define APIERROR(error) \
+ { std::cout << "API ERROR: " << error.code << " " << error.message \
+ << std::endl \
+ << " " << "Status: " << error.status \
+ << ", Classification: " << error.classification << std::endl\
+ << " " << "File: " << __FILE__ \
+ << " (Line: " << __LINE__ << ")" << std::endl \
+ ; \
+ }
+
+//
+// TRANSERROR prints all error info regarding an NdbTransaction
+//
+#define TRANSERROR(ndbTransaction) \
+ { NdbError error = ndbTransaction->getNdbError(); \
+ std::cout << "TRANS ERROR: " << error.code << " " << error.message \
+ << std::endl \
+ << " " << "Status: " << error.status \
+ << ", Classification: " << error.classification << std::endl \
+ << " " << "File: " << __FILE__ \
+ << " (Line: " << __LINE__ << ")" << std::endl \
+ ; \
+ printTransactionError(ndbTransaction); \
+ }
+
+void printTransactionError(NdbTransaction *ndbTransaction) {
+ const NdbOperation *ndbOp = NULL;
+ int i=0;
+
+ /****************************************************************
+ * Print NdbError object of every operations in the transaction *
+ ****************************************************************/
+ while ((ndbOp = ndbTransaction->getNextCompletedOperation(ndbOp)) != NULL) {
+ NdbError error = ndbOp->getNdbError();
+ std::cout << " OPERATION " << i+1 << ": "
+ << error.code << " " << error.message << std::endl
+ << " Status: " << error.status
+ << ", Classification: " << error.classification << std::endl;
+ i++;
+ }
+}
+
+
+//
+// Example insert
+// @param myNdb Ndb object representing NDB Cluster
+// @param myTransaction NdbTransaction used for transaction
+// @param myTable Table to insert into
+// @param error NdbError object returned in case of errors
+// @return -1 in case of failures, 0 otherwise
+//
+int insert(int transactionId, NdbTransaction* myTransaction,
+ const NdbDictionary::Table *myTable) {
+ NdbOperation *myOperation; // For other operations
+
+ myOperation = myTransaction->getNdbOperation(myTable);
+ if (myOperation == NULL) return -1;
+
+ if (myOperation->insertTuple() ||
+ myOperation->equal("ATTR1", transactionId) ||
+ myOperation->setValue("ATTR2", transactionId)) {
+ APIERROR(myOperation->getNdbError());
+ exit(-1);
+ }
+
+ return myTransaction->execute(NdbTransaction::NoCommit);
+}
+
+
+//
+// Execute function which re-executes (tries 10 times) the transaction
+// if there are temporary errors (e.g. the NDB Cluster is overloaded).
+// @return -1 failure, 1 success
+//
+int executeInsertTransaction(int transactionId, Ndb* myNdb,
+ const NdbDictionary::Table *myTable) {
+ int result = 0; // No result yet
+ int noOfRetriesLeft = 10;
+ NdbTransaction *myTransaction; // For other transactions
+ NdbError ndberror;
+
+ while (noOfRetriesLeft > 0 && !result) {
+
+ /*********************************
+ * Start and execute transaction *
+ *********************************/
+ myTransaction = myNdb->startTransaction();
+ if (myTransaction == NULL) {
+ APIERROR(myNdb->getNdbError());
+ ndberror = myNdb->getNdbError();
+ result = -1; // Failure
+ } else if (insert(transactionId, myTransaction, myTable) ||
+ insert(10000+transactionId, myTransaction, myTable) ||
+ myTransaction->execute(NdbTransaction::Commit)) {
+ TRANSERROR(myTransaction);
+ ndberror = myTransaction->getNdbError();
+ result = -1; // Failure
+ } else {
+ result = 1; // Success
+ }
+
+ /**********************************
+ * If failure, then analyze error *
+ **********************************/
+ if (result == -1) {
+ switch (ndberror.status) {
+ case NdbError::Success:
+ break;
+ case NdbError::TemporaryError:
+ std::cout << "Retrying transaction..." << std::endl;
+ sleep(TIME_TO_SLEEP_BETWEEN_TRANSACTION_RETRIES);
+ --noOfRetriesLeft;
+ result = 0; // No completed transaction yet
+ break;
+
+ case NdbError::UnknownResult:
+ case NdbError::PermanentError:
+ std::cout << "No retry of transaction..." << std::endl;
+ result = -1; // Permanent failure
+ break;
+ }
+ }
+
+ /*********************
+ * Close transaction *
+ *********************/
+ if (myTransaction != NULL) {
+ myNdb->closeTransaction(myTransaction);
+ }
+ }
+
+ if (result != 1) exit(-1);
+ return result;
+}
+
+
+int main()
+{
+ ndb_init();
+
+ Ndb_cluster_connection *cluster_connection=
+ new Ndb_cluster_connection(); // Object representing the cluster
+
+ int r= cluster_connection->connect(5 /* retries */,
+ 3 /* delay between retries */,
+ 1 /* verbose */);
+ if (r > 0)
+ {
+ std::cout
+ << "Cluster connect failed, possibly resolved with more retries.\n";
+ exit(-1);
+ }
+ else if (r < 0)
+ {
+ std::cout
+ << "Cluster connect failed.\n";
+ exit(-1);
+ }
+
+ if (cluster_connection->wait_until_ready(30,30))
+ {
+ std::cout << "Cluster was not ready within 30 secs." << std::endl;
+ exit(-1);
+ }
+
+ Ndb* myNdb= new Ndb( cluster_connection,
+ "TEST_DB_1" ); // Object representing the database
+
+ if (myNdb->init() == -1) {
+ APIERROR(myNdb->getNdbError());
+ exit(-1);
+ }
+
+ const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
+ if (myTable == NULL)
+ {
+ APIERROR(myDict->getNdbError());
+ return -1;
+ }
+ /************************************
+ * Execute some insert transactions *
+ ************************************/
+ for (int i = 10000; i < 20000; i++) {
+ executeInsertTransaction(i, myNdb, myTable);
+ }
+
+ delete myNdb;
+ delete cluster_connection;
+
+ ndb_end(0);
+ return 0;
+}
diff --git a/storage/ndb/ndbapi-examples/ndbapi_scan_example/Makefile b/storage/ndb/ndbapi-examples/ndbapi_scan_example/Makefile
new file mode 100644
index 00000000000..31886b02bf1
--- /dev/null
+++ b/storage/ndb/ndbapi-examples/ndbapi_scan_example/Makefile
@@ -0,0 +1,23 @@
+TARGET = ndbapi_scan
+SRCS = $(TARGET).cpp
+OBJS = $(TARGET).o
+CXX = g++
+CFLAGS = -g -c -Wall -fno-rtti -fno-exceptions
+CXXFLAGS = -g
+DEBUG =
+LFLAGS = -Wall
+TOP_SRCDIR = ../../..
+INCLUDE_DIR = $(TOP_SRCDIR)
+LIB_DIR = -L$(TOP_SRCDIR)/ndb/src/.libs \
+ -L$(TOP_SRCDIR)/libmysql_r/.libs \
+ -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+SYS_LIB =
+
+$(TARGET): $(OBJS)
+ $(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+
+$(TARGET).o: $(SRCS)
+ $(CXX) $(CFLAGS) -I$(INCLUDE_DIR)/include -I$(INCLUDE_DIR)/extra -I$(INCLUDE_DIR)/ndb/include -I$(INCLUDE_DIR)/ndb/include/ndbapi $(SRCS)
+
+clean:
+ rm -f *.o $(TARGET)
diff --git a/storage/ndb/ndbapi-examples/ndbapi_scan_example/ndbapi_scan.cpp b/storage/ndb/ndbapi-examples/ndbapi_scan_example/ndbapi_scan.cpp
new file mode 100644
index 00000000000..69ffd99b8ca
--- /dev/null
+++ b/storage/ndb/ndbapi-examples/ndbapi_scan_example/ndbapi_scan.cpp
@@ -0,0 +1,825 @@
+
+/* 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 */
+
+
+/*
+ * ndbapi_scan.cpp:
+ * Illustrates how to use the scan api in the NDBAPI.
+ * The example shows how to do scan, scan for update and scan for delete
+ * using NdbScanFilter and NdbScanOperation
+ *
+ * Classes and methods used in this example:
+ *
+ * Ndb_cluster_connection
+ * connect()
+ * wait_until_ready()
+ *
+ * Ndb
+ * init()
+ * getDictionary()
+ * startTransaction()
+ * closeTransaction()
+ *
+ * NdbTransaction
+ * getNdbScanOperation()
+ * execute()
+ *
+ * NdbScanOperation
+ * getValue()
+ * readTuples()
+ * nextResult()
+ * deleteCurrentTuple()
+ * updateCurrentTuple()
+ *
+ * const NdbDictionary::Dictionary
+ * getTable()
+ *
+ * const NdbDictionary::Table
+ * getColumn()
+ *
+ * const NdbDictionary::Column
+ * getLength()
+ *
+ * NdbOperation
+ * insertTuple()
+ * equal()
+ * setValue()
+ *
+ * NdbScanFilter
+ * begin()
+ * eq()
+ * end()
+ *
+ */
+
+
+#include <mysql.h>
+#include <mysqld_error.h>
+#include <NdbApi.hpp>
+// Used for cout
+#include <iostream>
+#include <stdio.h>
+
+/**
+ * Helper sleep function
+ */
+static void
+milliSleep(int milliseconds){
+ struct timeval sleeptime;
+ sleeptime.tv_sec = milliseconds / 1000;
+ sleeptime.tv_usec = (milliseconds - (sleeptime.tv_sec * 1000)) * 1000000;
+ select(0, 0, 0, 0, &sleeptime);
+}
+
+
+/**
+ * Helper sleep function
+ */
+#define PRINT_ERROR(code,msg) \
+ std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
+ << ", code: " << code \
+ << ", msg: " << msg << "." << std::endl
+#define MYSQLERROR(mysql) { \
+ PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
+ exit(-1); }
+#define APIERROR(error) { \
+ PRINT_ERROR(error.code,error.message); \
+ exit(-1); }
+
+struct Car
+{
+ /**
+ * Note memset, so that entire char-fields are cleared
+ * as all 20 bytes are significant (as type is char)
+ */
+ Car() { memset(this, 0, sizeof(* this)); }
+
+ unsigned int reg_no;
+ char brand[20];
+ char color[20];
+};
+
+/**
+ * Function to create table
+ */
+int create_table(MYSQL &mysql)
+{
+ while (mysql_query(&mysql,
+ "CREATE TABLE"
+ " GARAGE"
+ " (REG_NO INT UNSIGNED NOT NULL,"
+ " BRAND CHAR(20) NOT NULL,"
+ " COLOR CHAR(20) NOT NULL,"
+ " PRIMARY KEY USING HASH (REG_NO))"
+ " ENGINE=NDB"))
+ {
+ if (mysql_errno(&mysql) != ER_TABLE_EXISTS_ERROR)
+ MYSQLERROR(mysql);
+ std::cout << "MySQL Cluster already has example table: GARAGE. "
+ << "Dropping it..." << std::endl;
+ /**************
+ * Drop table *
+ **************/
+ if (mysql_query(&mysql, "DROP TABLE GARAGE"))
+ MYSQLERROR(mysql);
+ }
+ return 1;
+}
+
+
+int populate(Ndb * myNdb)
+{
+ int i;
+ Car cars[15];
+
+ const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("GARAGE");
+
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
+
+ /**
+ * Five blue mercedes
+ */
+ for (i = 0; i < 5; i++)
+ {
+ cars[i].reg_no = i;
+ sprintf(cars[i].brand, "Mercedes");
+ sprintf(cars[i].color, "Blue");
+ }
+
+ /**
+ * Five black bmw
+ */
+ for (i = 5; i < 10; i++)
+ {
+ cars[i].reg_no = i;
+ sprintf(cars[i].brand, "BMW");
+ sprintf(cars[i].color, "Black");
+ }
+
+ /**
+ * Five pink toyotas
+ */
+ for (i = 10; i < 15; i++)
+ {
+ cars[i].reg_no = i;
+ sprintf(cars[i].brand, "Toyota");
+ sprintf(cars[i].color, "Pink");
+ }
+
+ NdbTransaction* myTrans = myNdb->startTransaction();
+ if (myTrans == NULL)
+ APIERROR(myNdb->getNdbError());
+
+ for (i = 0; i < 15; i++)
+ {
+ NdbOperation* myNdbOperation = myTrans->getNdbOperation(myTable);
+ if (myNdbOperation == NULL)
+ APIERROR(myTrans->getNdbError());
+ myNdbOperation->insertTuple();
+ myNdbOperation->equal("REG_NO", cars[i].reg_no);
+ myNdbOperation->setValue("BRAND", cars[i].brand);
+ myNdbOperation->setValue("COLOR", cars[i].color);
+ }
+
+ int check = myTrans->execute(NdbTransaction::Commit);
+
+ myTrans->close();
+
+ return check != -1;
+}
+
+int scan_delete(Ndb* myNdb,
+ int column,
+ const char * color)
+
+{
+
+ // Scan all records exclusive and delete
+ // them one by one
+ int retryAttempt = 0;
+ const int retryMax = 10;
+ int deletedRows = 0;
+ int check;
+ NdbError err;
+ NdbTransaction *myTrans;
+ NdbScanOperation *myScanOp;
+
+ const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("GARAGE");
+
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
+
+ /**
+ * Loop as long as :
+ * retryMax not reached
+ * failed operations due to TEMPORARY erros
+ *
+ * Exit loop;
+ * retyrMax reached
+ * Permanent error (return -1)
+ */
+ while (true)
+ {
+ if (retryAttempt >= retryMax)
+ {
+ std::cout << "ERROR: has retried this operation " << retryAttempt
+ << " times, failing!" << std::endl;
+ return -1;
+ }
+
+ myTrans = myNdb->startTransaction();
+ if (myTrans == NULL)
+ {
+ const NdbError err = myNdb->getNdbError();
+
+ if (err.status == NdbError::TemporaryError)
+ {
+ milliSleep(50);
+ retryAttempt++;
+ continue;
+ }
+ std::cout << err.message << std::endl;
+ return -1;
+ }
+
+ /**
+ * Get a scan operation.
+ */
+ myScanOp = myTrans->getNdbScanOperation(myTable);
+ if (myScanOp == NULL)
+ {
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ return -1;
+ }
+
+ /**
+ * Define a result set for the scan.
+ */
+ if(myScanOp->readTuples(NdbOperation::LM_Exclusive) != 0)
+ {
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ return -1;
+ }
+
+ /**
+ * Use NdbScanFilter to define a search critera
+ */
+ NdbScanFilter filter(myScanOp) ;
+ if(filter.begin(NdbScanFilter::AND) < 0 ||
+ filter.cmp(NdbScanFilter::COND_EQ, column, color) < 0 ||
+ filter.end() < 0)
+ {
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ return -1;
+ }
+
+ /**
+ * Start scan (NoCommit since we are only reading at this stage);
+ */
+ if(myTrans->execute(NdbTransaction::NoCommit) != 0){
+ err = myTrans->getNdbError();
+ if(err.status == NdbError::TemporaryError){
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ milliSleep(50);
+ continue;
+ }
+ std::cout << err.code << std::endl;
+ std::cout << myTrans->getNdbError().code << std::endl;
+ myNdb->closeTransaction(myTrans);
+ return -1;
+ }
+
+
+ /**
+ * start of loop: nextResult(true) means that "parallelism" number of
+ * rows are fetched from NDB and cached in NDBAPI
+ */
+ while((check = myScanOp->nextResult(true)) == 0){
+ do
+ {
+ if (myScanOp->deleteCurrentTuple() != 0)
+ {
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ return -1;
+ }
+ deletedRows++;
+
+ /**
+ * nextResult(false) means that the records
+ * cached in the NDBAPI are modified before
+ * fetching more rows from NDB.
+ */
+ } while((check = myScanOp->nextResult(false)) == 0);
+
+ /**
+ * Commit when all cached tuple have been marked for deletion
+ */
+ if(check != -1)
+ {
+ check = myTrans->execute(NdbTransaction::Commit);
+ }
+
+ if(check == -1)
+ {
+ /**
+ * Create a new transaction, while keeping scan open
+ */
+ check = myTrans->restart();
+ }
+
+ /**
+ * Check for errors
+ */
+ err = myTrans->getNdbError();
+ if(check == -1)
+ {
+ if(err.status == NdbError::TemporaryError)
+ {
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ milliSleep(50);
+ continue;
+ }
+ }
+ /**
+ * End of loop
+ */
+ }
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ return 0;
+ }
+
+ if(myTrans!=0)
+ {
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ }
+ return -1;
+}
+
+
+int scan_update(Ndb* myNdb,
+ int update_column,
+ const char * before_color,
+ const char * after_color)
+
+{
+
+ // Scan all records exclusive and update
+ // them one by one
+ int retryAttempt = 0;
+ const int retryMax = 10;
+ int updatedRows = 0;
+ int check;
+ NdbError err;
+ NdbTransaction *myTrans;
+ NdbScanOperation *myScanOp;
+
+ const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("GARAGE");
+
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
+
+ /**
+ * Loop as long as :
+ * retryMax not reached
+ * failed operations due to TEMPORARY erros
+ *
+ * Exit loop;
+ * retyrMax reached
+ * Permanent error (return -1)
+ */
+ while (true)
+ {
+
+ if (retryAttempt >= retryMax)
+ {
+ std::cout << "ERROR: has retried this operation " << retryAttempt
+ << " times, failing!" << std::endl;
+ return -1;
+ }
+
+ myTrans = myNdb->startTransaction();
+ if (myTrans == NULL)
+ {
+ const NdbError err = myNdb->getNdbError();
+
+ if (err.status == NdbError::TemporaryError)
+ {
+ milliSleep(50);
+ retryAttempt++;
+ continue;
+ }
+ std::cout << err.message << std::endl;
+ return -1;
+ }
+
+ /**
+ * Get a scan operation.
+ */
+ myScanOp = myTrans->getNdbScanOperation(myTable);
+ if (myScanOp == NULL)
+ {
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ return -1;
+ }
+
+ /**
+ * Define a result set for the scan.
+ */
+ if( myScanOp->readTuples(NdbOperation::LM_Exclusive) )
+ {
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ return -1;
+ }
+
+ /**
+ * Use NdbScanFilter to define a search critera
+ */
+ NdbScanFilter filter(myScanOp) ;
+ if(filter.begin(NdbScanFilter::AND) < 0 ||
+ filter.cmp(NdbScanFilter::COND_EQ, update_column, before_color) <0||
+ filter.end() <0)
+ {
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ return -1;
+ }
+
+ /**
+ * Start scan (NoCommit since we are only reading at this stage);
+ */
+ if(myTrans->execute(NdbTransaction::NoCommit) != 0)
+ {
+ err = myTrans->getNdbError();
+ if(err.status == NdbError::TemporaryError){
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ milliSleep(50);
+ continue;
+ }
+ std::cout << myTrans->getNdbError().code << std::endl;
+ myNdb->closeTransaction(myTrans);
+ return -1;
+ }
+
+ /**
+ * start of loop: nextResult(true) means that "parallelism" number of
+ * rows are fetched from NDB and cached in NDBAPI
+ */
+ while((check = myScanOp->nextResult(true)) == 0){
+ do {
+ /**
+ * Get update operation
+ */
+ NdbOperation * myUpdateOp = myScanOp->updateCurrentTuple();
+ if (myUpdateOp == 0)
+ {
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ return -1;
+ }
+ updatedRows++;
+
+ /**
+ * do the update
+ */
+ myUpdateOp->setValue(update_column, after_color);
+ /**
+ * nextResult(false) means that the records
+ * cached in the NDBAPI are modified before
+ * fetching more rows from NDB.
+ */
+ } while((check = myScanOp->nextResult(false)) == 0);
+
+ /**
+ * NoCommit when all cached tuple have been updated
+ */
+ if(check != -1)
+ {
+ check = myTrans->execute(NdbTransaction::NoCommit);
+ }
+
+ /**
+ * Check for errors
+ */
+ err = myTrans->getNdbError();
+ if(check == -1)
+ {
+ if(err.status == NdbError::TemporaryError){
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ milliSleep(50);
+ continue;
+ }
+ }
+ /**
+ * End of loop
+ */
+ }
+
+ /**
+ * Commit all prepared operations
+ */
+ if(myTrans->execute(NdbTransaction::Commit) == -1)
+ {
+ if(err.status == NdbError::TemporaryError){
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ milliSleep(50);
+ continue;
+ }
+ }
+
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ return 0;
+ }
+
+
+ if(myTrans!=0)
+ {
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ }
+ return -1;
+}
+
+
+
+int scan_print(Ndb * myNdb)
+{
+// Scan all records exclusive and update
+ // them one by one
+ int retryAttempt = 0;
+ const int retryMax = 10;
+ int fetchedRows = 0;
+ int check;
+ NdbError err;
+ NdbTransaction *myTrans;
+ NdbScanOperation *myScanOp;
+ /* Result of reading attribute value, three columns:
+ REG_NO, BRAND, and COLOR
+ */
+ NdbRecAttr * myRecAttr[3];
+
+ const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("GARAGE");
+
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
+
+ /**
+ * Loop as long as :
+ * retryMax not reached
+ * failed operations due to TEMPORARY erros
+ *
+ * Exit loop;
+ * retyrMax reached
+ * Permanent error (return -1)
+ */
+ while (true)
+ {
+
+ if (retryAttempt >= retryMax)
+ {
+ std::cout << "ERROR: has retried this operation " << retryAttempt
+ << " times, failing!" << std::endl;
+ return -1;
+ }
+
+ myTrans = myNdb->startTransaction();
+ if (myTrans == NULL)
+ {
+ const NdbError err = myNdb->getNdbError();
+
+ if (err.status == NdbError::TemporaryError)
+ {
+ milliSleep(50);
+ retryAttempt++;
+ continue;
+ }
+ std::cout << err.message << std::endl;
+ return -1;
+ }
+ /*
+ * Define a scan operation.
+ * NDBAPI.
+ */
+ myScanOp = myTrans->getNdbScanOperation(myTable);
+ if (myScanOp == NULL)
+ {
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ return -1;
+ }
+
+ /**
+ * Read without locks, without being placed in lock queue
+ */
+ if( myScanOp->readTuples(NdbOperation::LM_CommittedRead) == -1)
+ {
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ return -1;
+ }
+
+ /**
+ * Define storage for fetched attributes.
+ * E.g., the resulting attributes of executing
+ * myOp->getValue("REG_NO") is placed in myRecAttr[0].
+ * No data exists in myRecAttr until transaction has commited!
+ */
+ myRecAttr[0] = myScanOp->getValue("REG_NO");
+ myRecAttr[1] = myScanOp->getValue("BRAND");
+ myRecAttr[2] = myScanOp->getValue("COLOR");
+ if(myRecAttr[0] ==NULL || myRecAttr[1] == NULL || myRecAttr[2]==NULL)
+ {
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ return -1;
+ }
+ /**
+ * Start scan (NoCommit since we are only reading at this stage);
+ */
+ if(myTrans->execute(NdbTransaction::NoCommit) != 0){
+ err = myTrans->getNdbError();
+ if(err.status == NdbError::TemporaryError){
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ milliSleep(50);
+ continue;
+ }
+ std::cout << err.code << std::endl;
+ std::cout << myTrans->getNdbError().code << std::endl;
+ myNdb->closeTransaction(myTrans);
+ return -1;
+ }
+
+ /**
+ * start of loop: nextResult(true) means that "parallelism" number of
+ * rows are fetched from NDB and cached in NDBAPI
+ */
+ while((check = myScanOp->nextResult(true)) == 0){
+ do {
+
+ fetchedRows++;
+ /**
+ * print REG_NO unsigned int
+ */
+ std::cout << myRecAttr[0]->u_32_value() << "\t";
+
+ /**
+ * print BRAND character string
+ */
+ std::cout << myRecAttr[1]->aRef() << "\t";
+
+ /**
+ * print COLOR character string
+ */
+ std::cout << myRecAttr[2]->aRef() << std::endl;
+
+ /**
+ * nextResult(false) means that the records
+ * cached in the NDBAPI are modified before
+ * fetching more rows from NDB.
+ */
+ } while((check = myScanOp->nextResult(false)) == 0);
+
+ }
+ myNdb->closeTransaction(myTrans);
+ return 1;
+ }
+ return -1;
+
+}
+
+
+int main()
+{
+ ndb_init();
+ MYSQL mysql;
+
+ /**************************************************************
+ * Connect to mysql server and create table *
+ **************************************************************/
+ {
+ if ( !mysql_init(&mysql) ) {
+ std::cout << "mysql_init failed\n";
+ exit(-1);
+ }
+ if ( !mysql_real_connect(&mysql, "localhost", "root", "", "",
+ 3306, "/tmp/mysql.sock", 0) )
+ MYSQLERROR(mysql);
+
+ mysql_query(&mysql, "CREATE DATABASE TEST_DB");
+ if (mysql_query(&mysql, "USE TEST_DB") != 0) MYSQLERROR(mysql);
+
+ create_table(mysql);
+ }
+
+ /**************************************************************
+ * Connect to ndb cluster *
+ **************************************************************/
+
+ Ndb_cluster_connection cluster_connection;
+ if (cluster_connection.connect(4, 5, 1))
+ {
+ std::cout << "Unable to connect to cluster within 30 secs." << std::endl;
+ exit(-1);
+ }
+ // Optionally connect and wait for the storage nodes (ndbd's)
+ if (cluster_connection.wait_until_ready(30,0) < 0)
+ {
+ std::cout << "Cluster was not ready within 30 secs.\n";
+ exit(-1);
+ }
+
+ Ndb myNdb(&cluster_connection,"TEST_DB");
+ if (myNdb.init(1024) == -1) { // Set max 1024 parallel transactions
+ APIERROR(myNdb.getNdbError());
+ exit(-1);
+ }
+
+ /*******************************************
+ * Check table definition *
+ *******************************************/
+ int column_color;
+ {
+ const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
+ const NdbDictionary::Table *t= myDict->getTable("GARAGE");
+
+ Car car;
+ if (t->getColumn("COLOR")->getLength() != sizeof(car.color) ||
+ t->getColumn("BRAND")->getLength() != sizeof(car.brand))
+ {
+ std::cout << "Wrong table definition" << std::endl;
+ exit(-1);
+ }
+ column_color= t->getColumn("COLOR")->getColumnNo();
+ }
+
+ if(populate(&myNdb) > 0)
+ std::cout << "populate: Success!" << std::endl;
+
+ if(scan_print(&myNdb) > 0)
+ std::cout << "scan_print: Success!" << std::endl << std::endl;
+
+ std::cout << "Going to delete all pink cars!" << std::endl;
+
+ {
+ /**
+ * Note! color needs to be of exact the same size as column defined
+ */
+ Car tmp;
+ sprintf(tmp.color, "Pink");
+ if(scan_delete(&myNdb, column_color, tmp.color) > 0)
+ std::cout << "scan_delete: Success!" << std::endl << std::endl;
+ }
+
+ if(scan_print(&myNdb) > 0)
+ std::cout << "scan_print: Success!" << std::endl << std::endl;
+
+ {
+ /**
+ * Note! color1 & 2 need to be of exact the same size as column defined
+ */
+ Car tmp1, tmp2;
+ sprintf(tmp1.color, "Blue");
+ sprintf(tmp2.color, "Black");
+ std::cout << "Going to update all " << tmp1.color
+ << " cars to " << tmp2.color << " cars!" << std::endl;
+ if(scan_update(&myNdb, column_color, tmp1.color, tmp2.color) > 0)
+ std::cout << "scan_update: Success!" << std::endl << std::endl;
+ }
+ if(scan_print(&myNdb) > 0)
+ std::cout << "scan_print: Success!" << std::endl << std::endl;
+
+ return 0;
+}
diff --git a/storage/ndb/ndbapi-examples/ndbapi_scan_example/readme.txt b/storage/ndb/ndbapi-examples/ndbapi_scan_example/readme.txt
new file mode 100644
index 00000000000..47cb4bf9ffa
--- /dev/null
+++ b/storage/ndb/ndbapi-examples/ndbapi_scan_example/readme.txt
@@ -0,0 +1,3 @@
+1. Set NDB_OS in Makefile
+2. Add path to libNDB_API.so in LD_LIBRARY_PATH
+3. Set NDB_CONNECTSTRING
diff --git a/storage/ndb/ndbapi-examples/ndbapi_simple_example/Makefile b/storage/ndb/ndbapi-examples/ndbapi_simple_example/Makefile
new file mode 100644
index 00000000000..0a59584fb66
--- /dev/null
+++ b/storage/ndb/ndbapi-examples/ndbapi_simple_example/Makefile
@@ -0,0 +1,23 @@
+TARGET = ndbapi_simple
+SRCS = $(TARGET).cpp
+OBJS = $(TARGET).o
+CXX = g++
+CFLAGS = -c -Wall -fno-rtti -fno-exceptions
+CXXFLAGS =
+DEBUG =
+LFLAGS = -Wall
+TOP_SRCDIR = ../../..
+INCLUDE_DIR = $(TOP_SRCDIR)
+LIB_DIR = -L$(TOP_SRCDIR)/ndb/src/.libs \
+ -L$(TOP_SRCDIR)/libmysql_r/.libs \
+ -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+SYS_LIB =
+
+$(TARGET): $(OBJS)
+ $(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+
+$(TARGET).o: $(SRCS)
+ $(CXX) $(CFLAGS) -I$(INCLUDE_DIR)/include -I$(INCLUDE_DIR)/ndb/include -I$(INCLUDE_DIR)/ndb/include/ndbapi $(SRCS)
+
+clean:
+ rm -f *.o $(TARGET)
diff --git a/storage/ndb/ndbapi-examples/ndbapi_simple_example/ndbapi_simple.cpp b/storage/ndb/ndbapi-examples/ndbapi_simple_example/ndbapi_simple.cpp
new file mode 100644
index 00000000000..152d4fa44af
--- /dev/null
+++ b/storage/ndb/ndbapi-examples/ndbapi_simple_example/ndbapi_simple.cpp
@@ -0,0 +1,278 @@
+/* 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 */
+
+/*
+ * ndbapi_simple.cpp: Using synchronous transactions in NDB API
+ *
+ * Correct output from this program is:
+ *
+ * ATTR1 ATTR2
+ * 0 10
+ * 1 1
+ * 2 12
+ * Detected that deleted tuple doesn't exist!
+ * 4 14
+ * 5 5
+ * 6 16
+ * 7 7
+ * 8 18
+ * 9 9
+ *
+ */
+
+#include <mysql.h>
+#include <NdbApi.hpp>
+// Used for cout
+#include <stdio.h>
+#include <iostream>
+
+static void run_application(MYSQL &, Ndb_cluster_connection &);
+
+#define PRINT_ERROR(code,msg) \
+ std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
+ << ", code: " << code \
+ << ", msg: " << msg << "." << std::endl
+#define MYSQLERROR(mysql) { \
+ PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
+ exit(-1); }
+#define APIERROR(error) { \
+ PRINT_ERROR(error.code,error.message); \
+ exit(-1); }
+
+int main()
+{
+ // ndb_init must be called first
+ ndb_init();
+
+ // connect to mysql server and cluster and run application
+ {
+ // Object representing the cluster
+ Ndb_cluster_connection cluster_connection;
+
+ // Connect to cluster management server (ndb_mgmd)
+ if (cluster_connection.connect(4 /* retries */,
+ 5 /* delay between retries */,
+ 1 /* verbose */))
+ {
+ std::cout << "Cluster management server was not ready within 30 secs.\n";
+ exit(-1);
+ }
+
+ // Optionally connect and wait for the storage nodes (ndbd's)
+ if (cluster_connection.wait_until_ready(30,0) < 0)
+ {
+ std::cout << "Cluster was not ready within 30 secs.\n";
+ exit(-1);
+ }
+
+ // connect to mysql server
+ MYSQL mysql;
+ if ( !mysql_init(&mysql) ) {
+ std::cout << "mysql_init failed\n";
+ exit(-1);
+ }
+ if ( !mysql_real_connect(&mysql, "localhost", "root", "", "",
+ 3306, "/tmp/mysql.sock", 0) )
+ MYSQLERROR(mysql);
+
+ // run the application code
+ run_application(mysql, cluster_connection);
+ }
+
+ ndb_end(0);
+
+ std::cout << "\nTo drop created table use:\n"
+ << "echo \"drop table MYTABLENAME\" | mysql TEST_DB_1 -u root\n";
+
+ return 0;
+}
+
+static void create_table(MYSQL &);
+static void do_insert(Ndb &);
+static void do_update(Ndb &);
+static void do_delete(Ndb &);
+static void do_read(Ndb &);
+
+static void run_application(MYSQL &mysql,
+ Ndb_cluster_connection &cluster_connection)
+{
+ /********************************************
+ * Connect to database via mysql-c *
+ ********************************************/
+ mysql_query(&mysql, "CREATE DATABASE TEST_DB_1");
+ if (mysql_query(&mysql, "USE TEST_DB_1") != 0) MYSQLERROR(mysql);
+ create_table(mysql);
+
+ /********************************************
+ * Connect to database via NdbApi *
+ ********************************************/
+ // Object representing the database
+ Ndb myNdb( &cluster_connection, "TEST_DB_1" );
+ if (myNdb.init()) APIERROR(myNdb.getNdbError());
+
+ /*
+ * Do different operations on database
+ */
+ do_insert(myNdb);
+ do_update(myNdb);
+ do_delete(myNdb);
+ do_read(myNdb);
+}
+
+/*********************************************************
+ * Create a table named MYTABLENAME if it does not exist *
+ *********************************************************/
+static void create_table(MYSQL &mysql)
+{
+ if (mysql_query(&mysql,
+ "CREATE TABLE"
+ " MYTABLENAME"
+ " (ATTR1 INT UNSIGNED NOT NULL PRIMARY KEY,"
+ " ATTR2 INT UNSIGNED NOT NULL)"
+ " ENGINE=NDB"))
+ MYSQLERROR(mysql);
+}
+
+/**************************************************************************
+ * Using 5 transactions, insert 10 tuples in table: (0,0),(1,1),...,(9,9) *
+ **************************************************************************/
+static void do_insert(Ndb &myNdb)
+{
+ const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
+
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
+
+ for (int i = 0; i < 5; i++) {
+ NdbTransaction *myTransaction= myNdb.startTransaction();
+ if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
+
+ NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
+ if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myOperation->insertTuple();
+ myOperation->equal("ATTR1", i);
+ myOperation->setValue("ATTR2", i);
+
+ myOperation= myTransaction->getNdbOperation(myTable);
+ if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myOperation->insertTuple();
+ myOperation->equal("ATTR1", i+5);
+ myOperation->setValue("ATTR2", i+5);
+
+ if (myTransaction->execute( NdbTransaction::Commit ) == -1)
+ APIERROR(myTransaction->getNdbError());
+
+ myNdb.closeTransaction(myTransaction);
+ }
+}
+
+/*****************************************************************
+ * Update the second attribute in half of the tuples (adding 10) *
+ *****************************************************************/
+static void do_update(Ndb &myNdb)
+{
+ const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
+
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
+
+ for (int i = 0; i < 10; i+=2) {
+ NdbTransaction *myTransaction= myNdb.startTransaction();
+ if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
+
+ NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
+ if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myOperation->updateTuple();
+ myOperation->equal( "ATTR1", i );
+ myOperation->setValue( "ATTR2", i+10);
+
+ if( myTransaction->execute( NdbTransaction::Commit ) == -1 )
+ APIERROR(myTransaction->getNdbError());
+
+ myNdb.closeTransaction(myTransaction);
+ }
+}
+
+/*************************************************
+ * Delete one tuple (the one with primary key 3) *
+ *************************************************/
+static void do_delete(Ndb &myNdb)
+{
+ const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
+
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
+
+ NdbTransaction *myTransaction= myNdb.startTransaction();
+ if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
+
+ NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
+ if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myOperation->deleteTuple();
+ myOperation->equal( "ATTR1", 3 );
+
+ if (myTransaction->execute(NdbTransaction::Commit) == -1)
+ APIERROR(myTransaction->getNdbError());
+
+ myNdb.closeTransaction(myTransaction);
+}
+
+/*****************************
+ * Read and print all tuples *
+ *****************************/
+static void do_read(Ndb &myNdb)
+{
+ const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
+
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
+
+ std::cout << "ATTR1 ATTR2" << std::endl;
+
+ for (int i = 0; i < 10; i++) {
+ NdbTransaction *myTransaction= myNdb.startTransaction();
+ if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
+
+ NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
+ if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myOperation->readTuple(NdbOperation::LM_Read);
+ myOperation->equal("ATTR1", i);
+
+ NdbRecAttr *myRecAttr= myOperation->getValue("ATTR2", NULL);
+ if (myRecAttr == NULL) APIERROR(myTransaction->getNdbError());
+
+ if(myTransaction->execute( NdbTransaction::Commit ) == -1)
+ if (i == 3) {
+ std::cout << "Detected that deleted tuple doesn't exist!" << std::endl;
+ } else {
+ APIERROR(myTransaction->getNdbError());
+ }
+
+ if (i != 3) {
+ printf(" %2d %2d\n", i, myRecAttr->u_32_value());
+ }
+ myNdb.closeTransaction(myTransaction);
+ }
+}
diff --git a/storage/ndb/ndbapi-examples/ndbapi_simple_index_example/Makefile b/storage/ndb/ndbapi-examples/ndbapi_simple_index_example/Makefile
new file mode 100644
index 00000000000..d4356055935
--- /dev/null
+++ b/storage/ndb/ndbapi-examples/ndbapi_simple_index_example/Makefile
@@ -0,0 +1,23 @@
+TARGET = ndbapi_simple_index
+SRCS = $(TARGET).cpp
+OBJS = $(TARGET).o
+CXX = g++
+CFLAGS = -c -Wall -fno-rtti -fno-exceptions
+CXXFLAGS =
+DEBUG =
+LFLAGS = -Wall
+TOP_SRCDIR = ../../..
+INCLUDE_DIR = $(TOP_SRCDIR)
+LIB_DIR = -L$(TOP_SRCDIR)/ndb/src/.libs \
+ -L$(TOP_SRCDIR)/libmysql_r/.libs \
+ -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+SYS_LIB =
+
+$(TARGET): $(OBJS)
+ $(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+
+$(TARGET).o: $(SRCS)
+ $(CXX) $(CFLAGS) -I$(INCLUDE_DIR)/include -I$(INCLUDE_DIR)/ndb/include -I$(INCLUDE_DIR)/ndb/include/ndbapi $(SRCS)
+
+clean:
+ rm -f *.o $(TARGET)
diff --git a/storage/ndb/ndbapi-examples/ndbapi_simple_index_example/ndbapi_simple_index.cpp b/storage/ndb/ndbapi-examples/ndbapi_simple_index_example/ndbapi_simple_index.cpp
new file mode 100644
index 00000000000..5afaf6078d1
--- /dev/null
+++ b/storage/ndb/ndbapi-examples/ndbapi_simple_index_example/ndbapi_simple_index.cpp
@@ -0,0 +1,254 @@
+/* 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 */
+
+//
+// ndbapi_simple_index.cpp: Using secondary indexes in NDB API
+//
+// Correct output from this program is:
+//
+// ATTR1 ATTR2
+// 0 10
+// 1 1
+// 2 12
+// Detected that deleted tuple doesn't exist!
+// 4 14
+// 5 5
+// 6 16
+// 7 7
+// 8 18
+// 9 9
+
+#include <mysql.h>
+#include <NdbApi.hpp>
+
+// Used for cout
+#include <stdio.h>
+#include <iostream>
+
+#define PRINT_ERROR(code,msg) \
+ std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
+ << ", code: " << code \
+ << ", msg: " << msg << "." << std::endl
+#define MYSQLERROR(mysql) { \
+ PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
+ exit(-1); }
+#define APIERROR(error) { \
+ PRINT_ERROR(error.code,error.message); \
+ exit(-1); }
+
+int main()
+{
+ ndb_init();
+ MYSQL mysql;
+
+ /**************************************************************
+ * Connect to mysql server and create table *
+ **************************************************************/
+ {
+ if ( !mysql_init(&mysql) ) {
+ std::cout << "mysql_init failed\n";
+ exit(-1);
+ }
+ if ( !mysql_real_connect(&mysql, "localhost", "root", "", "",
+ 3306, "/tmp/mysql.sock", 0) )
+ MYSQLERROR(mysql);
+
+ mysql_query(&mysql, "CREATE DATABASE TEST_DB_1");
+ if (mysql_query(&mysql, "USE TEST_DB_1") != 0) MYSQLERROR(mysql);
+
+ if (mysql_query(&mysql,
+ "CREATE TABLE"
+ " MYTABLENAME"
+ " (ATTR1 INT UNSIGNED,"
+ " ATTR2 INT UNSIGNED NOT NULL,"
+ " PRIMARY KEY USING HASH (ATTR1),"
+ " UNIQUE MYINDEXNAME USING HASH (ATTR2))"
+ " ENGINE=NDB"))
+ MYSQLERROR(mysql);
+ }
+
+ /**************************************************************
+ * Connect to ndb cluster *
+ **************************************************************/
+
+ Ndb_cluster_connection *cluster_connection=
+ new Ndb_cluster_connection(); // Object representing the cluster
+
+ if (cluster_connection->connect(5,3,1))
+ {
+ std::cout << "Connect to cluster management server failed.\n";
+ exit(-1);
+ }
+
+ if (cluster_connection->wait_until_ready(30,30))
+ {
+ std::cout << "Cluster was not ready within 30 secs.\n";
+ exit(-1);
+ }
+
+ Ndb* myNdb = new Ndb( cluster_connection,
+ "TEST_DB_1" ); // Object representing the database
+ if (myNdb->init() == -1) {
+ APIERROR(myNdb->getNdbError());
+ exit(-1);
+ }
+
+ const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
+ const NdbDictionary::Index *myIndex= myDict->getIndex("MYINDEXNAME","MYTABLENAME");
+ if (myIndex == NULL)
+ APIERROR(myDict->getNdbError());
+
+ /**************************************************************************
+ * Using 5 transactions, insert 10 tuples in table: (0,0),(1,1),...,(9,9) *
+ **************************************************************************/
+ for (int i = 0; i < 5; i++) {
+ NdbTransaction *myTransaction= myNdb->startTransaction();
+ if (myTransaction == NULL) APIERROR(myNdb->getNdbError());
+
+ NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
+ if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myOperation->insertTuple();
+ myOperation->equal("ATTR1", i);
+ myOperation->setValue("ATTR2", i);
+
+ myOperation = myTransaction->getNdbOperation(myTable);
+ if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myOperation->insertTuple();
+ myOperation->equal("ATTR1", i+5);
+ myOperation->setValue("ATTR2", i+5);
+
+ if (myTransaction->execute( NdbTransaction::Commit ) == -1)
+ APIERROR(myTransaction->getNdbError());
+
+ myNdb->closeTransaction(myTransaction);
+ }
+
+ /*****************************************
+ * Read and print all tuples using index *
+ *****************************************/
+ std::cout << "ATTR1 ATTR2" << std::endl;
+
+ for (int i = 0; i < 10; i++) {
+ NdbTransaction *myTransaction= myNdb->startTransaction();
+ if (myTransaction == NULL) APIERROR(myNdb->getNdbError());
+
+ NdbIndexOperation *myIndexOperation=
+ myTransaction->getNdbIndexOperation(myIndex);
+ if (myIndexOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myIndexOperation->readTuple(NdbOperation::LM_Read);
+ myIndexOperation->equal("ATTR2", i);
+
+ NdbRecAttr *myRecAttr= myIndexOperation->getValue("ATTR1", NULL);
+ if (myRecAttr == NULL) APIERROR(myTransaction->getNdbError());
+
+ if(myTransaction->execute( NdbTransaction::Commit ) != -1)
+ printf(" %2d %2d\n", myRecAttr->u_32_value(), i);
+
+ myNdb->closeTransaction(myTransaction);
+ }
+
+ /*****************************************************************
+ * Update the second attribute in half of the tuples (adding 10) *
+ *****************************************************************/
+ for (int i = 0; i < 10; i+=2) {
+ NdbTransaction *myTransaction= myNdb->startTransaction();
+ if (myTransaction == NULL) APIERROR(myNdb->getNdbError());
+
+ NdbIndexOperation *myIndexOperation=
+ myTransaction->getNdbIndexOperation(myIndex);
+ if (myIndexOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myIndexOperation->updateTuple();
+ myIndexOperation->equal( "ATTR2", i );
+ myIndexOperation->setValue( "ATTR2", i+10);
+
+ if( myTransaction->execute( NdbTransaction::Commit ) == -1 )
+ APIERROR(myTransaction->getNdbError());
+
+ myNdb->closeTransaction(myTransaction);
+ }
+
+ /*************************************************
+ * Delete one tuple (the one with primary key 3) *
+ *************************************************/
+ {
+ NdbTransaction *myTransaction= myNdb->startTransaction();
+ if (myTransaction == NULL) APIERROR(myNdb->getNdbError());
+
+ NdbIndexOperation *myIndexOperation=
+ myTransaction->getNdbIndexOperation(myIndex);
+ if (myIndexOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myIndexOperation->deleteTuple();
+ myIndexOperation->equal( "ATTR2", 3 );
+
+ if (myTransaction->execute(NdbTransaction::Commit) == -1)
+ APIERROR(myTransaction->getNdbError());
+
+ myNdb->closeTransaction(myTransaction);
+ }
+
+ /*****************************
+ * Read and print all tuples *
+ *****************************/
+ {
+ std::cout << "ATTR1 ATTR2" << std::endl;
+
+ for (int i = 0; i < 10; i++) {
+ NdbTransaction *myTransaction= myNdb->startTransaction();
+ if (myTransaction == NULL) APIERROR(myNdb->getNdbError());
+
+ NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
+ if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myOperation->readTuple(NdbOperation::LM_Read);
+ myOperation->equal("ATTR1", i);
+
+ NdbRecAttr *myRecAttr= myOperation->getValue("ATTR2", NULL);
+ if (myRecAttr == NULL) APIERROR(myTransaction->getNdbError());
+
+ if(myTransaction->execute( NdbTransaction::Commit ) == -1)
+ if (i == 3) {
+ std::cout << "Detected that deleted tuple doesn't exist!\n";
+ } else {
+ APIERROR(myTransaction->getNdbError());
+ }
+
+ if (i != 3) {
+ printf(" %2d %2d\n", i, myRecAttr->u_32_value());
+ }
+ myNdb->closeTransaction(myTransaction);
+ }
+ }
+
+ /**************
+ * Drop table *
+ **************/
+ if (mysql_query(&mysql, "DROP TABLE MYTABLENAME"))
+ MYSQLERROR(mysql);
+
+ delete myNdb;
+ delete cluster_connection;
+
+ ndb_end(0);
+ return 0;
+}