summaryrefslogtreecommitdiff
path: root/ndb/examples
diff options
context:
space:
mode:
authorunknown <magnus@neptunus.(none)>2004-04-14 10:53:21 +0200
committerunknown <magnus@neptunus.(none)>2004-04-14 10:53:21 +0200
commit6386c55cee50bad6a9979d1fab28e03bb8612ca7 (patch)
tree3fbbacf704304b69228474b9f03549ccd585a017 /ndb/examples
parent0ba6cb48d84f1ff951d09871a96be6cdef3f2c3c (diff)
downloadmariadb-git-6386c55cee50bad6a9979d1fab28e03bb8612ca7.tar.gz
Initial revision of NDB Cluster files
BitKeeper/etc/logging_ok: Logging to logging@openlogging.org accepted
Diffstat (limited to 'ndb/examples')
-rw-r--r--ndb/examples/Makefile26
-rw-r--r--ndb/examples/configurations/demos.tarbin0 -> 40960 bytes
-rw-r--r--ndb/examples/ndbapi_async_example/Makefile34
-rw-r--r--ndb/examples/ndbapi_async_example/ndbapi_async.cpp505
-rw-r--r--ndb/examples/ndbapi_async_example/readme.txt3
-rw-r--r--ndb/examples/ndbapi_example1/Makefile33
-rw-r--r--ndb/examples/ndbapi_example1/ndbapi_example1.cpp193
-rw-r--r--ndb/examples/ndbapi_example2/Makefile33
-rw-r--r--ndb/examples/ndbapi_example2/ndbapi_example2.cpp110
-rw-r--r--ndb/examples/ndbapi_example3/Makefile33
-rw-r--r--ndb/examples/ndbapi_example3/ndbapi_example3.cpp202
-rw-r--r--ndb/examples/ndbapi_example4/Makefile33
-rw-r--r--ndb/examples/ndbapi_example4/ndbapi_example4.cpp252
-rw-r--r--ndb/examples/ndbapi_example5/Makefile33
-rw-r--r--ndb/examples/ndbapi_example5/ndbapi_example5.cpp230
-rw-r--r--ndb/examples/ndbapi_scan_example/Makefile35
-rw-r--r--ndb/examples/ndbapi_scan_example/ndbapi_scan.cpp824
-rw-r--r--ndb/examples/ndbapi_scan_example/readme.txt3
-rw-r--r--ndb/examples/select_all/Makefile33
-rw-r--r--ndb/examples/select_all/select_all.cpp258
20 files changed, 2873 insertions, 0 deletions
diff --git a/ndb/examples/Makefile b/ndb/examples/Makefile
new file mode 100644
index 00000000000..e1fb71a1817
--- /dev/null
+++ b/ndb/examples/Makefile
@@ -0,0 +1,26 @@
+-include .defs.mk
+
+#ifneq ($(C++),)
+#OPTS = CC=$(CC) CXX=$(C++)
+#endif
+
+# XXX ndbapi_example4 commented out until fixed
+BIN_DIRS := ndbapi_example1 ndbapi_example2 ndbapi_example3 $(ndbapi_example4) \
+ ndbapi_example5 select_all
+
+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
+
+cleanall: clean
+tidy: clean
+distclean: clean
+
diff --git a/ndb/examples/configurations/demos.tar b/ndb/examples/configurations/demos.tar
new file mode 100644
index 00000000000..d8cae90ec5b
--- /dev/null
+++ b/ndb/examples/configurations/demos.tar
Binary files differ
diff --git a/ndb/examples/ndbapi_async_example/Makefile b/ndb/examples/ndbapi_async_example/Makefile
new file mode 100644
index 00000000000..7910a4a1d12
--- /dev/null
+++ b/ndb/examples/ndbapi_async_example/Makefile
@@ -0,0 +1,34 @@
+-include ../../Defs.mk
+#NDB_OS = OS_YOU_ARE_RUNNING_ON
+#NDB_OS = LINUX
+#You need to set the NDB_OS variable here (LINUX, SOLARIS, MACOSX)
+TARGET = ndbapi_async
+SRCS = ndbapi_async.cpp
+OBJS = ndbapi_async.o
+CC = g++
+CFLAGS = -c -Wall -fno-rtti -D$(NDB_OS)
+DEBUG =
+LFLAGS = -Wall
+INCLUDE_DIR = ../../include
+LIB_DIR = ../../lib
+ifeq ($(NDB_OS), SOLARIS)
+# Here is the definition of system libraries necessary for Solaris 7
+SYS_LIB = -lpthread -lsocket -lnsl -lrt
+endif
+ifeq ($(NDB_OS), LINUX)
+# Here is the definition of system libraries necessary for Linux 2.4
+SYS_LIB = -lpthread
+endif
+ifeq ($(NDB_OS), MACOSX)
+# Here is the definition of system libraries necessary for Mac OS X
+SYS_LIB =
+endif
+
+$(TARGET): $(OBJS)
+ $(CC) $(LFLAGS) -L$(LIB_DIR) -lNDB_API $(OBJS) $(SYS_LIB) -o $(TARGET)
+
+$(TARGET).o: $(SRCS)
+ $(CC) $(CFLAGS) -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi $(SRCS)
+
+clean:
+ rm -f *.o $(TARGET)
diff --git a/ndb/examples/ndbapi_async_example/ndbapi_async.cpp b/ndb/examples/ndbapi_async_example/ndbapi_async.cpp
new file mode 100644
index 00000000000..078ac0c5cbf
--- /dev/null
+++ b/ndb/examples/ndbapi_async_example/ndbapi_async.cpp
@@ -0,0 +1,505 @@
+
+
+/* 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
+ * init()
+ * waitUntilRead()
+ * getDictionary()
+ * startTransaction()
+ * closeTransaction()
+ * sendPollNdb()
+ * getNdbError()
+ *
+ * NdbConnection
+ * getNdbOperation()
+ * executeAsynchPrepare()
+ * getNdbError()
+ *
+ * NdbDictionary::Dictionary
+ * getTable()
+ * dropTable()
+ * createTable()
+ * getNdbError()
+ *
+ * NdbDictionary::Column
+ * setName()
+ * setPrimaryKey()
+ * setType()
+ * setLength()
+ * setNullable()
+ *
+ * NdbDictionary::Table
+ * setName()
+ * addColumn()
+ *
+ * NdbOperation
+ * insertTuple()
+ * equal()
+ * setValue()
+ *
+ */
+
+
+#include <NdbApi.hpp>
+#include <NdbScanFilter.hpp>
+#include <iostream> // Used for cout
+
+#ifdef SOLARIS
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#if defined LINUX || defined MACOSX
+#include <time.h>
+#include <unistd.h>
+#endif
+
+/**
+ * Helper sleep function
+ */
+int
+milliSleep(int milliseconds){
+ int result = 0;
+ struct timespec sleeptime;
+ sleeptime.tv_sec = milliseconds / 1000;
+ sleeptime.tv_nsec = (milliseconds - (sleeptime.tv_sec * 1000)) * 1000000;
+ result = nanosleep(&sleeptime, NULL);
+ return result;
+}
+
+/**
+ * error printout macro
+ */
+#define APIERROR(error) \
+ { std::cout << "Error in " << __FILE__ << ", line:" << __LINE__ << ", code:" \
+ << error.code << ", msg: " << error.message << "." << std::endl; \
+ 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 NdbConnection
+ */
+typedef struct {
+ NdbConnection* 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(NdbConnection * 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;
+
+/**
+ * Helper function for callback(...)
+ */
+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, NdbConnection* 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(Ndb * myNdb)
+{
+ NdbDictionary::Table myTable;
+ NdbDictionary::Column myColumn;
+
+ NdbDictionary::Dictionary* myDict = myNdb->getDictionary();
+
+ /*********************************************************
+ * Create a table named GARAGE if it does not exist *
+ *********************************************************/
+ if (myDict->getTable("GARAGE") != NULL)
+ {
+ std::cout << "NDB already has example table: GARAGE. "
+ << "Dropping it..." << std::endl;
+ if(myDict->dropTable("GARAGE") == -1)
+ {
+ std::cout << "Failed to drop: GARAGE." << std::endl;
+ exit(1);
+ }
+ }
+
+ myTable.setName("GARAGE");
+
+/**
+ * Column REG_NO
+ */
+ myColumn.setName("REG_NO");
+ myColumn.setPrimaryKey(true);
+ myColumn.setType(NdbDictionary::Column::Unsigned);
+ myColumn.setLength(1);
+ myColumn.setNullable(false);
+ myTable.addColumn(myColumn);
+
+/**
+ * Column BRAND
+ */
+ myColumn.setName("BRAND");
+ myColumn.setPrimaryKey(false);
+ myColumn.setType(NdbDictionary::Column::Char);
+ myColumn.setLength(20);
+ myColumn.setNullable(false);
+ myTable.addColumn(myColumn);
+
+/**
+ * Column COLOR
+ */
+ myColumn.setName("COLOR");
+ myColumn.setPrimaryKey(false);
+ myColumn.setType(NdbDictionary::Column::Char);
+ myColumn.setLength(20);
+ myColumn.setNullable(false);
+ myTable.addColumn(myColumn);
+
+ if (myDict->createTable(myTable) == -1) {
+ APIERROR(myDict->getNdbError());
+ }
+ 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(NdbConnection * 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
+
+ async_callback_t * cb;
+ int retries;
+ 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);
+ }
+ // Error check. If error, then maybe table GARAGE is not in database
+ myNdbOperation = transaction[current].conn->getNdbOperation("GARAGE");
+ 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(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* myNdb = new Ndb( "TEST_DB" ); // Object representing the database
+
+ /*******************************************
+ * Initialize NDB and wait until its ready *
+ *******************************************/
+ if (myNdb->init(1024) == -1) { // Set max 1024 parallel transactions
+ APIERROR(myNdb->getNdbError());
+ }
+
+ if (myNdb->waitUntilReady(30) != 0) {
+ std::cout << "NDB was not ready within 30 secs." << std::endl;
+ exit(-1);
+ }
+ create_table(myNdb);
+
+
+ /**
+ * 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/ndb/examples/ndbapi_async_example/readme.txt b/ndb/examples/ndbapi_async_example/readme.txt
new file mode 100644
index 00000000000..47cb4bf9ffa
--- /dev/null
+++ b/ndb/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/ndb/examples/ndbapi_example1/Makefile b/ndb/examples/ndbapi_example1/Makefile
new file mode 100644
index 00000000000..eb0142ce673
--- /dev/null
+++ b/ndb/examples/ndbapi_example1/Makefile
@@ -0,0 +1,33 @@
+-include .defs.mk
+#NDB_OS = OS_YOU_ARE_RUNNING_ON
+#You need to set the NDB_OS variable here
+TARGET = ndbapi_example1
+SRCS = ndbapi_example1.cpp
+OBJS = ndbapi_example1.o
+CXX = g++
+CFLAGS = -c -Wall -fno-rtti -fno-exceptions
+DEBUG =
+LFLAGS = -Wall
+INCLUDE_DIR = ../../include
+LIB_DIR = ../../lib
+ifeq ($(NDB_OS), SOLARIS)
+# Here is the definition of system libraries necessary for Solaris 7
+SYS_LIB =
+endif
+ifeq ($(NDB_OS), LINUX)
+# Here is the definition of system libraries necessary for Linux 2.4
+SYS_LIB =
+endif
+ifeq ($(NDB_OS), MACOSX)
+# Here is the definition of system libraries necessary for Mac OS X
+SYS_LIB =
+endif
+
+$(TARGET): $(OBJS)
+ $(CXX) $(LFLAGS) -L$(LIB_DIR) $(OBJS) -lNDB_API $(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/ndb/examples/ndbapi_example1/ndbapi_example1.cpp b/ndb/examples/ndbapi_example1/ndbapi_example1.cpp
new file mode 100644
index 00000000000..879d86de824
--- /dev/null
+++ b/ndb/examples/ndbapi_example1/ndbapi_example1.cpp
@@ -0,0 +1,193 @@
+/* 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_example1.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 <NdbApi.hpp>
+
+// Used for cout
+#include <stdio.h>
+#include <iostream>
+
+#define APIERROR(error) \
+ { std::cout << "Error in " << __FILE__ << ", line:" << __LINE__ << ", code:" \
+ << error.code << ", msg: " << error.message << "." << std::endl; \
+ exit(-1); }
+
+int main()
+{
+ Ndb* myNdb = new Ndb( "TEST_DB_1" ); // Object representing the database
+ NdbDictionary::Table myTable;
+ NdbDictionary::Column myColumn;
+
+ NdbConnection *myConnection; // For other transactions
+ NdbOperation *myOperation; // For other operations
+ NdbRecAttr *myRecAttr; // Result of reading attribute value
+
+ /********************************************
+ * Initialize NDB and wait until it's ready *
+ ********************************************/
+ if (myNdb->init() == -1) {
+ APIERROR(myNdb->getNdbError());
+ exit(-1);
+ }
+
+ if (myNdb->waitUntilReady(30) != 0) {
+ std::cout << "NDB was not ready within 30 secs." << std::endl;
+ exit(-1);
+ }
+
+ NdbDictionary::Dictionary* myDict = myNdb->getDictionary();
+
+ /*********************************************************
+ * Create a table named MYTABLENAME if it does not exist *
+ *********************************************************/
+ if (myDict->getTable("MYTABLENAME") != NULL) {
+ std::cout << "NDB already has example table: MYTABLENAME." << std::endl;
+ exit(-1);
+ }
+
+ myTable.setName("MYTABLENAME");
+
+ myColumn.setName("ATTR1");
+ myColumn.setPrimaryKey(true);
+ myColumn.setType(NdbDictionary::Column::Unsigned);
+ myColumn.setLength(1);
+ myColumn.setNullable(false);
+ myTable.addColumn(myColumn);
+
+ myColumn.setName("ATTR2");
+ myColumn.setPrimaryKey(false);
+ myColumn.setType(NdbDictionary::Column::Unsigned);
+ myColumn.setLength(1);
+ myColumn.setNullable(false);
+ myTable.addColumn(myColumn);
+
+ if (myDict->createTable(myTable) == -1)
+ APIERROR(myDict->getNdbError());
+
+ /**************************************************************************
+ * Using 5 transactions, insert 10 tuples in table: (0,0),(1,1),...,(9,9) *
+ **************************************************************************/
+ for (int i = 0; i < 5; i++) {
+ myConnection = myNdb->startTransaction();
+ if (myConnection == NULL) APIERROR(myNdb->getNdbError());
+
+ myOperation = myConnection->getNdbOperation("MYTABLENAME");
+ if (myOperation == NULL) APIERROR(myConnection->getNdbError());
+
+ myOperation->insertTuple();
+ myOperation->equal("ATTR1", i);
+ myOperation->setValue("ATTR2", i);
+
+ myOperation = myConnection->getNdbOperation("MYTABLENAME");
+ if (myOperation == NULL) APIERROR(myConnection->getNdbError());
+
+ myOperation->insertTuple();
+ myOperation->equal("ATTR1", i+5);
+ myOperation->setValue("ATTR2", i+5);
+
+ if (myConnection->execute( Commit ) == -1)
+ APIERROR(myConnection->getNdbError());
+
+ myNdb->closeTransaction(myConnection);
+ }
+
+ /*****************************************************************
+ * Update the second attribute in half of the tuples (adding 10) *
+ *****************************************************************/
+ for (int i = 0; i < 10; i+=2) {
+ myConnection = myNdb->startTransaction();
+ if (myConnection == NULL) APIERROR(myNdb->getNdbError());
+
+ myOperation = myConnection->getNdbOperation("MYTABLENAME");
+ if (myOperation == NULL) APIERROR(myConnection->getNdbError());
+
+ myOperation->updateTuple();
+ myOperation->equal( "ATTR1", i );
+ myOperation->setValue( "ATTR2", i+10);
+
+ if( myConnection->execute( Commit ) == -1 )
+ APIERROR(myConnection->getNdbError());
+
+ myNdb->closeTransaction(myConnection);
+ }
+
+ /*************************************************
+ * Delete one tuple (the one with primary key 3) *
+ *************************************************/
+ myConnection = myNdb->startTransaction();
+ if (myConnection == NULL) APIERROR(myNdb->getNdbError());
+
+ myOperation = myConnection->getNdbOperation("MYTABLENAME");
+ if (myOperation == NULL)
+ APIERROR(myConnection->getNdbError());
+
+ myOperation->deleteTuple();
+ myOperation->equal( "ATTR1", 3 );
+
+ if (myConnection->execute(Commit) == -1)
+ APIERROR(myConnection->getNdbError());
+
+ myNdb->closeTransaction(myConnection);
+
+ /*****************************
+ * Read and print all tuples *
+ *****************************/
+ std::cout << "ATTR1 ATTR2" << std::endl;
+
+ for (int i = 0; i < 10; i++) {
+ myConnection = myNdb->startTransaction();
+ if (myConnection == NULL) APIERROR(myNdb->getNdbError());
+
+ myOperation = myConnection->getNdbOperation("MYTABLENAME");
+ if (myOperation == NULL) APIERROR(myConnection->getNdbError());
+
+ myOperation->readTuple();
+ myOperation->equal("ATTR1", i);
+
+ myRecAttr = myOperation->getValue("ATTR2", NULL);
+ if (myRecAttr == NULL) APIERROR(myConnection->getNdbError());
+
+ if(myConnection->execute( Commit ) == -1)
+ if (i == 3) {
+ std::cout << "Detected that deleted tuple doesn't exist!" << std::endl;
+ } else {
+ APIERROR(myConnection->getNdbError());
+ }
+
+ if (i != 3) {
+ printf(" %2d %2d\n", i, myRecAttr->u_32_value());
+ }
+ myNdb->closeTransaction(myConnection);
+ }
+ delete myNdb;
+}
diff --git a/ndb/examples/ndbapi_example2/Makefile b/ndb/examples/ndbapi_example2/Makefile
new file mode 100644
index 00000000000..17b2b1528fc
--- /dev/null
+++ b/ndb/examples/ndbapi_example2/Makefile
@@ -0,0 +1,33 @@
+-include .defs.mk
+#NDB_OS = OS_YOU_ARE_RUNNING_ON
+#You need to set the NDB_OS variable here
+TARGET = ndbapi_example2
+SRCS = ndbapi_example2.cpp
+OBJS = ndbapi_example2.o
+CXX = g++
+CFLAGS = -c -Wall -fno-rtti -fno-exceptions
+DEBUG =
+LFLAGS = -Wall
+INCLUDE_DIR = ../../include
+LIB_DIR = ../../lib
+ifeq ($(NDB_OS), SOLARIS)
+# Here is the definition of system libraries necessary for Solaris 7
+SYS_LIB =
+endif
+ifeq ($(NDB_OS), LINUX)
+# Here is the definition of system libraries necessary for Linux 2.4
+SYS_LIB =
+endif
+ifeq ($(NDB_OS), MACOSX)
+# Here is the definition of system libraries necessary for Mac OS X
+SYS_LIB =
+endif
+
+$(TARGET): $(OBJS)
+ $(CXX) $(LFLAGS) -L$(LIB_DIR) $(OBJS) -lNDB_API $(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/ndb/examples/ndbapi_example2/ndbapi_example2.cpp b/ndb/examples/ndbapi_example2/ndbapi_example2.cpp
new file mode 100644
index 00000000000..1c61721c037
--- /dev/null
+++ b/ndb/examples/ndbapi_example2/ndbapi_example2.cpp
@@ -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 */
+
+//
+// ndbapi_example2.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, NdbConnection* NdbObject, void* aObject);
+
+int main()
+{
+ Ndb* myNdb = new Ndb( "TEST_DB_2" ); // Object representing the database
+
+ NdbConnection* myNdbConnection[2]; // For transactions
+ NdbOperation* myNdbOperation; // For operations
+
+ /*******************************************
+ * Initialize NDB and wait until its ready *
+ *******************************************/
+ if (myNdb->init(2) == -1) { // Want two parallel insert transactions
+ APIERROR(myNdb->getNdbError());
+ exit(-1);
+ }
+
+ if (myNdb->waitUntilReady(30) != 0) {
+ std::cout << "NDB was not ready within 30 secs." << std::endl;
+ exit(-1);
+ }
+
+ /******************************************************
+ * Insert (we do two insert transactions in parallel) *
+ ******************************************************/
+ for (int i = 0; i < 2; i++) {
+ myNdbConnection[i] = myNdb->startTransaction();
+ if (myNdbConnection[i] == NULL) APIERROR(myNdb->getNdbError());
+
+ myNdbOperation = myNdbConnection[i]->getNdbOperation("MYTABLENAME");
+ // Error check. If error, then maybe table MYTABLENAME is not in database
+ if (myNdbOperation == NULL) APIERROR(myNdbConnection[i]->getNdbError());
+
+ myNdbOperation->insertTuple();
+ myNdbOperation->equal("ATTR1", 20 + i);
+ myNdbOperation->setValue("ATTR2", 20 + i);
+
+ // Prepare transaction (the transaction is NOT yet sent to NDB)
+ myNdbConnection[i]->executeAsynchPrepare(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(myNdbConnection[i]);
+
+ delete myNdb;
+}
+
+/*
+ * callback : This is called when the transaction is polled
+ *
+ * (This function must have three arguments:
+ * - The result of the transaction,
+ * - The NdbConnection object, and
+ * - A pointer to an arbitrary object.)
+ */
+
+static void
+callback(int result, NdbConnection* 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/ndb/examples/ndbapi_example3/Makefile b/ndb/examples/ndbapi_example3/Makefile
new file mode 100644
index 00000000000..bd6f0182aa4
--- /dev/null
+++ b/ndb/examples/ndbapi_example3/Makefile
@@ -0,0 +1,33 @@
+-include .defs.mk
+#NDB_OS = OS_YOU_ARE_RUNNING_ON
+#You need to set the NDB_OS variable here
+TARGET = ndbapi_example3
+SRCS = ndbapi_example3.cpp
+OBJS = ndbapi_example3.o
+CXX = g++
+CFLAGS = -c -Wall -fno-rtti -fno-exceptions
+DEBUG =
+LFLAGS = -Wall
+INCLUDE_DIR = ../../include
+LIB_DIR = ../../lib
+ifeq ($(NDB_OS), SOLARIS)
+# Here is the definition of system libraries necessary for Solaris 7
+SYS_LIB =
+endif
+ifeq ($(NDB_OS), LINUX)
+# Here is the definition of system libraries necessary for Linux 2.4
+SYS_LIB =
+endif
+ifeq ($(NDB_OS), MACOSX)
+# Here is the definition of system libraries necessary for Mac OS X
+SYS_LIB =
+endif
+
+$(TARGET): $(OBJS)
+ $(CXX) $(LFLAGS) -L$(LIB_DIR) $(OBJS) -lNDB_API $(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/ndb/examples/ndbapi_example3/ndbapi_example3.cpp b/ndb/examples/ndbapi_example3/ndbapi_example3.cpp
new file mode 100644
index 00000000000..36d2cf1608c
--- /dev/null
+++ b/ndb/examples/ndbapi_example3/ndbapi_example3.cpp
@@ -0,0 +1,202 @@
+/* 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_example3.cpp: Error handling and transaction retries
+//
+// Execute ndbapi_example1 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::Ndbexecute(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 \
+ ; \
+ }
+
+//
+// CONERROR prints all error info regarding an NdbConnection
+//
+#define CONERROR(ndbConnection) \
+ { NdbError error = ndbConnection->getNdbError(); \
+ std::cout << "CON ERROR: " << error.code << " " << error.message \
+ << std::endl \
+ << " " << "Status: " << error.status \
+ << ", Classification: " << error.classification << std::endl \
+ << " " << "File: " << __FILE__ \
+ << " (Line: " << __LINE__ << ")" << std::endl \
+ ; \
+ printTransactionError(ndbConnection); \
+ }
+
+void printTransactionError(NdbConnection *ndbConnection) {
+ const NdbOperation *ndbOp = NULL;
+ int i=0;
+
+ /****************************************************************
+ * Print NdbError object of every operations in the transaction *
+ ****************************************************************/
+ while ((ndbOp = ndbConnection->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 myConnection NdbConnection used for transaction
+// @param error NdbError object returned in case of errors
+// @return -1 in case of failures, 0 otherwise
+//
+int insert(int transactionId, NdbConnection* myConnection) {
+ NdbOperation *myOperation; // For other operations
+
+ myOperation = myConnection->getNdbOperation("MYTABLENAME");
+ if (myOperation == NULL) return -1;
+
+ if (myOperation->insertTuple() ||
+ myOperation->equal("ATTR1", transactionId) ||
+ myOperation->setValue("ATTR2", transactionId)) {
+ APIERROR(myOperation->getNdbError());
+ exit(-1);
+ }
+
+ return myConnection->execute(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) {
+ int result = 0; // No result yet
+ int noOfRetriesLeft = 10;
+ NdbConnection *myConnection; // For other transactions
+ NdbError ndberror;
+
+ while (noOfRetriesLeft > 0 && !result) {
+
+ /*********************************
+ * Start and execute transaction *
+ *********************************/
+ myConnection = myNdb->startTransaction();
+ if (myConnection == NULL) {
+ APIERROR(myNdb->getNdbError());
+ ndberror = myNdb->getNdbError();
+ result = -1; // Failure
+ } else if (insert(transactionId, myConnection) ||
+ insert(10000+transactionId, myConnection) ||
+ myConnection->execute(Commit)) {
+ CONERROR(myConnection);
+ ndberror = myConnection->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 (myConnection != NULL) {
+ myNdb->closeTransaction(myConnection);
+ }
+ }
+
+ if (result != 1) exit(-1);
+ return result;
+}
+
+
+int main()
+{
+ Ndb* myNdb = new Ndb( "TEST_DB_1" ); // Object representing the database
+
+ /*******************************************
+ * Initialize NDB and wait until its ready *
+ *******************************************/
+ if (myNdb->init() == -1) {
+ APIERROR(myNdb->getNdbError());
+ exit(-1);
+ }
+
+ if (myNdb->waitUntilReady(30) != 0) {
+ std::cout << "NDB was not ready within 30 secs." << std::endl;
+ exit(-1);
+ }
+
+ /************************************
+ * Execute some insert transactions *
+ ************************************/
+ for (int i = 10000; i < 20000; i++) {
+ executeInsertTransaction(i, myNdb);
+ }
+
+ delete myNdb;
+}
diff --git a/ndb/examples/ndbapi_example4/Makefile b/ndb/examples/ndbapi_example4/Makefile
new file mode 100644
index 00000000000..b0ce852d347
--- /dev/null
+++ b/ndb/examples/ndbapi_example4/Makefile
@@ -0,0 +1,33 @@
+-include .defs.mk
+#NDB_OS = OS_YOU_ARE_RUNNING_ON
+#You need to set the NDB_OS variable here
+TARGET = ndbapi_example4
+SRCS = ndbapi_example4.cpp
+OBJS = ndbapi_example4.o
+CXX = g++
+CFLAGS = -c -Wall -fno-rtti -fno-exceptions
+DEBUG =
+LFLAGS = -Wall
+INCLUDE_DIR = ../../include
+LIB_DIR = ../../lib
+ifeq ($(NDB_OS), SOLARIS)
+# Here is the definition of system libraries necessary for Solaris 7
+SYS_LIB =
+endif
+ifeq ($(NDB_OS), LINUX)
+# Here is the definition of system libraries necessary for Linux 2.4
+SYS_LIB =
+endif
+ifeq ($(NDB_OS), MACOSX)
+# Here is the definition of system libraries necessary for Mac OS X
+SYS_LIB =
+endif
+
+$(TARGET): $(OBJS)
+ $(CXX) $(LFLAGS) -L$(LIB_DIR) $(OBJS) -lNDB_API $(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/ndb/examples/ndbapi_example4/ndbapi_example4.cpp b/ndb/examples/ndbapi_example4/ndbapi_example4.cpp
new file mode 100644
index 00000000000..520172b9b0c
--- /dev/null
+++ b/ndb/examples/ndbapi_example4/ndbapi_example4.cpp
@@ -0,0 +1,252 @@
+/* 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_example4.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 <NdbApi.hpp>
+
+// Used for cout
+#include <stdio.h>
+#include <iostream>
+
+#define APIERROR(error) \
+ { std::cout << "Error in " << __FILE__ << ", line:" << __LINE__ << ", code:" \
+ << error.code << ", msg: " << error.message << "." << std::endl; \
+ exit(-1); }
+
+int main()
+{
+ Ndb* myNdb = new Ndb( "TEST_DB_1" ); // Object representing the database
+ NdbDictionary::Table myTable;
+ NdbDictionary::Column myColumn;
+ NdbDictionary::Index myIndex;
+
+ NdbConnection *myConnection; // For transactions
+ NdbOperation *myOperation; // For primary key operations
+ NdbIndexOperation *myIndexOperation; // For index operations
+ NdbRecAttr *myRecAttr; // Result of reading attribute value
+
+ /********************************************
+ * Initialize NDB and wait until it's ready *
+ ********************************************/
+ if (myNdb->init() == -1) {
+ APIERROR(myNdb->getNdbError());
+ exit(-1);
+ }
+
+ if (myNdb->waitUntilReady(30) != 0) {
+ std::cout << "NDB was not ready within 30 secs." << std::endl;
+ exit(-1);
+ }
+
+ /*********************************************************
+ * Create a table named MYTABLENAME if it does not exist *
+ *********************************************************/
+ NdbDictionary::Dictionary* myDict = myNdb->getDictionary();
+ if (myDict->getTable("MYTABLENAME") != NULL) {
+ std::cout << "NDB already has example table: MYTABLENAME." << std::endl;
+ exit(-1);
+ }
+
+ myTable.setName("MYTABLENAME");
+
+ myColumn.setName("ATTR1");
+ myColumn.setPrimaryKey(true);
+ myColumn.setType(NdbDictionary::Column::Unsigned);
+ myColumn.setLength(1);
+ myColumn.setNullable(false);
+ myTable.addColumn(myColumn);
+
+ myColumn.setName("ATTR2");
+ myColumn.setPrimaryKey(false);
+ myColumn.setType(NdbDictionary::Column::Unsigned);
+ myColumn.setLength(1);
+ myColumn.setNullable(false);
+ myTable.addColumn(myColumn);
+
+ if (myDict->createTable(myTable) == -1)
+ APIERROR(myDict->getNdbError());
+
+
+ /**********************************************************
+ * Create an index named MYINDEXNAME if it does not exist *
+ **********************************************************/
+ if (myDict->getIndex("MYINDEXNAME", "MYTABLENAME") != NULL) {
+ std::cout << "NDB already has example index: MYINDEXNAME." << std::endl;
+ exit(-1);
+ }
+
+ myIndex.setName("MYINDEXNAME");
+ myIndex.setTable("MYTABLENAME");
+ myIndex.setType(NdbDictionary::Index::UniqueHashIndex);
+ const char* attr_arr[] = {"ATTR2"};
+ myIndex.addIndexColumns(1, attr_arr);
+
+ if (myDict->createIndex(myIndex) == -1)
+ APIERROR(myDict->getNdbError());
+
+
+ /**************************************************************************
+ * Using 5 transactions, insert 10 tuples in table: (0,0),(1,1),...,(9,9) *
+ **************************************************************************/
+ for (int i = 0; i < 5; i++) {
+ myConnection = myNdb->startTransaction();
+ if (myConnection == NULL) APIERROR(myNdb->getNdbError());
+
+ myOperation = myConnection->getNdbOperation("MYTABLENAME");
+ if (myOperation == NULL) APIERROR(myConnection->getNdbError());
+
+ myOperation->insertTuple();
+ myOperation->equal("ATTR1", i);
+ myOperation->setValue("ATTR2", i);
+
+ myOperation = myConnection->getNdbOperation("MYTABLENAME");
+ if (myOperation == NULL) APIERROR(myConnection->getNdbError());
+
+ myOperation->insertTuple();
+ myOperation->equal("ATTR1", i+5);
+ myOperation->setValue("ATTR2", i+5);
+
+ if (myConnection->execute( Commit ) == -1)
+ APIERROR(myConnection->getNdbError());
+
+ myNdb->closeTransaction(myConnection);
+ }
+
+ /*****************************************
+ * Read and print all tuples using index *
+ *****************************************/
+ std::cout << "ATTR1 ATTR2" << std::endl;
+
+ for (int i = 0; i < 10; i++) {
+ myConnection = myNdb->startTransaction();
+ if (myConnection == NULL) APIERROR(myNdb->getNdbError());
+
+ myIndexOperation = myConnection->getNdbIndexOperation("MYINDEXNAME",
+ "MYTABLENAME");
+ if (myIndexOperation == NULL) APIERROR(myConnection->getNdbError());
+
+ myIndexOperation->readTuple();
+ myIndexOperation->equal("ATTR2", i);
+
+ myRecAttr = myIndexOperation->getValue("ATTR1", NULL);
+ if (myRecAttr == NULL) APIERROR(myConnection->getNdbError());
+
+ if(myConnection->execute( Commit ) != -1)
+ printf(" %2d %2d\n", myRecAttr->u_32_value(), i);
+ }
+ myNdb->closeTransaction(myConnection);
+
+ /*****************************************************************
+ * Update the second attribute in half of the tuples (adding 10) *
+ *****************************************************************/
+ for (int i = 0; i < 10; i+=2) {
+ myConnection = myNdb->startTransaction();
+ if (myConnection == NULL) APIERROR(myNdb->getNdbError());
+
+ myIndexOperation = myConnection->getNdbIndexOperation("MYINDEXNAME",
+ "MYTABLENAME");
+ if (myIndexOperation == NULL) APIERROR(myConnection->getNdbError());
+
+ myIndexOperation->updateTuple();
+ myIndexOperation->equal( "ATTR2", i );
+ myIndexOperation->setValue( "ATTR2", i+10);
+
+ if( myConnection->execute( Commit ) == -1 )
+ APIERROR(myConnection->getNdbError());
+
+ myNdb->closeTransaction(myConnection);
+ }
+
+ /*************************************************
+ * Delete one tuple (the one with primary key 3) *
+ *************************************************/
+ myConnection = myNdb->startTransaction();
+ if (myConnection == NULL) APIERROR(myNdb->getNdbError());
+
+ myIndexOperation = myConnection->getNdbIndexOperation("MYINDEXNAME",
+ "MYTABLENAME");
+ if (myIndexOperation == NULL)
+ APIERROR(myConnection->getNdbError());
+
+ myIndexOperation->deleteTuple();
+ myIndexOperation->equal( "ATTR2", 3 );
+
+ if (myConnection->execute(Commit) == -1)
+ APIERROR(myConnection->getNdbError());
+
+ myNdb->closeTransaction(myConnection);
+
+ /*****************************
+ * Read and print all tuples *
+ *****************************/
+ std::cout << "ATTR1 ATTR2" << std::endl;
+
+ for (int i = 0; i < 10; i++) {
+ myConnection = myNdb->startTransaction();
+ if (myConnection == NULL) APIERROR(myNdb->getNdbError());
+
+ myOperation = myConnection->getNdbOperation("MYTABLENAME");
+ if (myOperation == NULL) APIERROR(myConnection->getNdbError());
+
+ myOperation->readTuple();
+ myOperation->equal("ATTR1", i);
+
+ myRecAttr = myOperation->getValue("ATTR2", NULL);
+ if (myRecAttr == NULL) APIERROR(myConnection->getNdbError());
+
+ if(myConnection->execute( Commit ) == -1)
+ if (i == 3) {
+ std::cout << "Detected that deleted tuple doesn't exist!" << std::endl;
+ } else {
+ APIERROR(myConnection->getNdbError());
+ }
+
+ if (i != 3) {
+ printf(" %2d %2d\n", i, myRecAttr->u_32_value());
+ }
+ myNdb->closeTransaction(myConnection);
+ }
+
+ /**************
+ * Drop index *
+ **************/
+ if (myDict->dropIndex("MYINDEXNAME", "MYTABLENAME") == -1)
+ APIERROR(myDict->getNdbError());
+
+ /**************
+ * Drop table *
+ **************/
+ if (myDict->dropTable("MYTABLENAME") == -1)
+ APIERROR(myDict->getNdbError());
+
+ delete myNdb;
+}
diff --git a/ndb/examples/ndbapi_example5/Makefile b/ndb/examples/ndbapi_example5/Makefile
new file mode 100644
index 00000000000..e2e3f06374a
--- /dev/null
+++ b/ndb/examples/ndbapi_example5/Makefile
@@ -0,0 +1,33 @@
+-include .defs.mk
+#NDB_OS = OS_YOU_ARE_RUNNING_ON
+#You need to set the NDB_OS variable here
+TARGET = ndbapi_example5
+SRCS = ndbapi_example5.cpp
+OBJS = ndbapi_example5.o
+CXX = g++
+CFLAGS = -c -Wall -fno-rtti -fno-exceptions
+DEBUG =
+LFLAGS = -Wall
+INCLUDE_DIR = ../../include
+LIB_DIR = ../../lib
+ifeq ($(NDB_OS), SOLARIS)
+# Here is the definition of system libraries necessary for Solaris 7
+SYS_LIB =
+endif
+ifeq ($(NDB_OS), LINUX)
+# Here is the definition of system libraries necessary for Linux 2.4
+SYS_LIB =
+endif
+ifeq ($(NDB_OS), MACOSX)
+# Here is the definition of system libraries necessary for Mac OS X
+SYS_LIB =
+endif
+
+$(TARGET): $(OBJS)
+ $(CXX) $(LFLAGS) -L$(LIB_DIR) $(OBJS) -lNDB_API $(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/ndb/examples/ndbapi_example5/ndbapi_example5.cpp b/ndb/examples/ndbapi_example5/ndbapi_example5.cpp
new file mode 100644
index 00000000000..a9d3099883c
--- /dev/null
+++ b/ndb/examples/ndbapi_example5/ndbapi_example5.cpp
@@ -0,0 +1,230 @@
+/* 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_example5.cpp: Using API level events in NDB API
+ */
+
+#include <NdbApi.hpp>
+#include <NdbEventOperation.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 mysqlcluster client;
+ *
+ * shell> mysqlcluster -u root
+ * mysql> create database TEST_DB;
+ * mysql> use TEST_DB;
+ * mysql> create table TAB0 (COL0 int primary key, COL1 int, COL11 int);
+ *
+ * In another window start ndbapi_example5, wait until properly started
+ *
+ * mysql> insert into TAB0 values (1,2,3);
+ * mysql> insert into TAB0 values (2,2,3);
+ * mysql> insert into TAB0 values (3,2,9);
+ * mysql>
+ *
+ * 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); }
+
+Ndb* myCreateNdb();
+int myCreateEvent(Ndb* myNdb,
+ const char *eventName,
+ const char *eventTableName,
+ const char **eventComlumnName,
+ const int noEventComlumnName);
+
+int main()
+{
+ Ndb* myNdb = myCreateNdb();
+ NdbDictionary::Dictionary *myDict;
+
+ const char *eventName = "CHNG_IN_TAB0";
+ const char *eventTableName = "TAB0";
+ const int noEventColumnName = 3;
+ const char *eventColumnName[noEventColumnName] =
+ {"COL0",
+ "COL1",
+ "COL11"};
+
+ myDict = myNdb->getDictionary();
+
+ // 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) {
+ printf("Event operation creation failed\n");
+ exit(-1);
+ }
+
+ 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");
+ if (op->execute()) { // This starts changes to "start flowing"
+ printf("operationd execution failed\n");
+ exit(-1);
+ }
+
+ 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 failiure 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;
+ }
+ 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(" post[%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 eventsanymore
+ myNdb->dropEventOperation(op);
+
+ j++;
+ }
+
+ myDict->dropEvent(eventName); // remove event from database
+
+ delete myNdb;
+}
+
+Ndb* myCreateNdb()
+{
+ Ndb* myNdb = new Ndb("TEST_DB");
+
+ /********************************************
+ * Initialize NDB and wait until it's ready *
+ ********************************************/
+ if (myNdb->init() == -1) {
+ APIERROR(myNdb->getNdbError());
+ exit(-1);
+ }
+
+ if (myNdb->waitUntilReady(30) != 0) {
+ std::cout << "NDB was not ready within 30 secs." << std::endl;
+ exit(-1);
+ }
+
+ return myNdb;
+}
+
+int myCreateEvent(Ndb* myNdb,
+ const char *eventName,
+ const char *eventTableName,
+ const char **eventColumnName,
+ const int noEventColumnName)
+{
+ NdbDictionary::Dictionary *myDict = myNdb->getDictionary();
+
+ if (!myDict) {
+ printf("Event Creation failedDictionary not found");
+ exit(-1);
+ }
+
+ NdbDictionary::Event myEvent(eventName);
+ myEvent.setTable(eventTableName);
+ myEvent.addTableEvent(NdbDictionary::Event::TE_ALL);
+ // myEvent.addTableEvent(NdbDictionary::Event::TE_INSERT);
+ // myEvent.addTableEvent(NdbDictionary::Event::TE_UPDATE);
+ // myEvent.addTableEvent(NdbDictionary::Event::TE_DELETE);
+
+ for (int i = 0; i < noEventColumnName; i++)
+ myEvent.addEventColumn(eventColumnName[i]);
+
+ int res = myDict->createEvent(myEvent); // Add event to database
+
+ if (res == 0)
+ myEvent.print();
+ else {
+ printf("Event creation failed\n");
+ printf("trying drop Event, maybe event exists\n");
+ res = myDict->dropEvent(eventName);
+ if (res)
+ exit(-1);
+ // try again
+ res = myDict->createEvent(myEvent); // Add event to database
+ if (res)
+ exit(-1);
+ }
+
+ return res;
+}
diff --git a/ndb/examples/ndbapi_scan_example/Makefile b/ndb/examples/ndbapi_scan_example/Makefile
new file mode 100644
index 00000000000..6e53317f8bf
--- /dev/null
+++ b/ndb/examples/ndbapi_scan_example/Makefile
@@ -0,0 +1,35 @@
+-include ../../Defs.mk
+#NDB_OS = OS_YOU_ARE_RUNNING_ON
+#You need to set the NDB_OS variable here (LINUX, SOLARIS, MACOSX)
+#NDB_OS = LINUX
+
+TARGET = ndbapi_scan
+SRCS = ndbapi_scan.cpp
+OBJS = ndbapi_scan.o
+CC = g++
+CFLAGS = -c -Wall -fno-rtti
+DEBUG =
+LFLAGS = -Wall
+INCLUDE_DIR = ../../include
+LIB_DIR = ../../lib
+ifeq ($(NDB_OS), SOLARIS)
+# Here is the definition of system libraries necessary for Solaris 7
+SYS_LIB = -lpthread -lsocket -lnsl -lrt
+endif
+ifeq ($(NDB_OS), LINUX)
+# Here is the definition of system libraries necessary for Linux 2.4
+SYS_LIB = -lpthread
+endif
+ifeq ($(NDB_OS), MACOSX)
+# Here is the definition of system libraries necessary for Mac OS X
+SYS_LIB =
+endif
+
+$(TARGET): $(OBJS)
+ $(CC) $(LFLAGS) -L$(LIB_DIR) -lNDB_API $(OBJS) $(SYS_LIB) -o $(TARGET)
+
+$(TARGET).o: $(SRCS)
+ $(CC) $(CFLAGS) -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi $(SRCS)
+
+clean:
+ rm -f *.o $(TARGET)
diff --git a/ndb/examples/ndbapi_scan_example/ndbapi_scan.cpp b/ndb/examples/ndbapi_scan_example/ndbapi_scan.cpp
new file mode 100644
index 00000000000..186afdb9471
--- /dev/null
+++ b/ndb/examples/ndbapi_scan_example/ndbapi_scan.cpp
@@ -0,0 +1,824 @@
+
+/* 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
+ * init()
+ * waitUntilRead()
+ * getDictionary()
+ * startTransaction()
+ * closeTransaction()
+ * sendPreparedTransactions()
+ * pollNdb()
+ *
+ * NdbConnection
+ * getNdbOperation()
+ * executeAsynchPrepare()
+ * getNdbError()
+ * executeScan()
+ * nextScanResult()
+ *
+ * NdbDictionary::Dictionary
+ * getTable()
+ * dropTable()
+ * createTable()
+ *
+ * NdbDictionary::Column
+ * setName()
+ * setPrimaryKey()
+ * setType()
+ * setLength()
+ * setNullable()
+ *
+ * NdbDictionary::Table
+ * setName()
+ * addColumn()
+ *
+ * NdbOperation
+ * insertTuple()
+ * equal()
+ * setValue()
+ * openScanRead()
+ * openScanExclusive()
+ *
+ * NdbRecAttr
+ * aRef()
+ * u_32_value()
+ *
+ * NdbResultSet
+ * nextResult()
+ * deleteTuple()
+ * updateTuple()
+ *
+ * NdbScanOperation
+ * getValue()
+ * readTuplesExclusive()
+ *
+ * NdbScanFilter
+ * begin()
+ * eq()
+ * end()
+ *
+ *
+ */
+
+
+#include <NdbApi.hpp>
+#include <NdbScanFilter.hpp>
+// Used for cout
+#include <iostream>
+
+#ifdef SOLARIS
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#if defined LINUX || defined MACOSX
+#include <time.h>
+#include <unistd.h>
+#endif
+
+/**
+ * Helper sleep function
+ */
+int
+milliSleep(int milliseconds){
+ int result = 0;
+ struct timespec sleeptime;
+ sleeptime.tv_sec = milliseconds / 1000;
+ sleeptime.tv_nsec = (milliseconds - (sleeptime.tv_sec * 1000)) * 1000000;
+ result = nanosleep(&sleeptime, NULL);
+ return result;
+}
+
+
+/**
+ * Helper sleep function
+ */
+#define APIERROR(error) \
+ { std::cout << "Error in " << __FILE__ << ", line:" << __LINE__ << ", code:" \
+ << error.code << ", msg: " << error.message << "." << std::endl; \
+ exit(-1); }
+
+/*
+ * callback : This is called when the transaction is polled
+ *
+ * (This function must have three arguments:
+ * - The result of the transaction,
+ * - The NdbConnection object, and
+ * - A pointer to an arbitrary object.)
+ */
+static void
+callback(int result, NdbConnection* myTrans, void* aObject)
+{
+ if (result == -1) {
+ std::cout << "In callback: " << std::endl;
+ /**
+ * Put error checking code here (see ndb_async_example)
+ */
+ APIERROR(myTrans->getNdbError());
+ } else {
+ /**
+ * Ok!
+ */
+ return;
+ }
+}
+
+/**
+ * Function to create table
+ */
+int create_table(Ndb * myNdb)
+{
+ NdbDictionary::Table myTable;
+ NdbDictionary::Column myColumn;
+
+ NdbDictionary::Dictionary* myDict = myNdb->getDictionary();
+
+ /*********************************************************
+ * Create a table named GARAGE if it does not exist *
+ *********************************************************/
+ if (myDict->getTable("GARAGE") != NULL) {
+ std::cout << "NDB already has example table: GARAGE. "
+ << "Dropping it..." << std::endl;
+ if(myDict->dropTable("GARAGE") == -1)
+ {
+ std::cout << "Failed to drop: GARAGE." << std::endl;
+ exit(1);
+ }
+ }
+
+ myTable.setName("GARAGE");
+
+ myColumn.setName("REG_NO");
+ myColumn.setPrimaryKey(true);
+ myColumn.setType(NdbDictionary::Column::Unsigned);
+ myColumn.setLength(1);
+ myColumn.setNullable(false);
+ myTable.addColumn(myColumn);
+
+ myColumn.setName("BRAND");
+ myColumn.setPrimaryKey(false);
+ myColumn.setType(NdbDictionary::Column::Char);
+ myColumn.setLength(20);
+ myColumn.setNullable(false);
+ myTable.addColumn(myColumn);
+
+
+ myColumn.setName("COLOR");
+ myColumn.setPrimaryKey(false);
+ myColumn.setType(NdbDictionary::Column::Char);
+ myColumn.setLength(20);
+ myColumn.setNullable(false);
+ myTable.addColumn(myColumn);
+
+ if (myDict->createTable(myTable) == -1) {
+ APIERROR(myDict->getNdbError());
+ return -1;
+ }
+ return 1;
+}
+
+
+int populate(Ndb * myNdb)
+{
+ NdbConnection* myNdbConnection[15]; // For transactions
+ NdbOperation* myNdbOperation; // For operations
+ /******************************************************
+ * Insert (we do 15 insert transactions in parallel) *
+ ******************************************************/
+ /**
+ * Five blue mercedes
+ */
+ for (int i = 0; i < 5; i++)
+ {
+ myNdbConnection[i] = myNdb->startTransaction();
+ if (myNdbConnection[i] == NULL)
+ APIERROR(myNdb->getNdbError());
+ myNdbOperation = myNdbConnection[i]->getNdbOperation("GARAGE");
+ // Error check. If error, then maybe table GARAGE is not in database
+ if (myNdbOperation == NULL)
+ APIERROR(myNdbConnection[i]->getNdbError());
+ myNdbOperation->insertTuple();
+ myNdbOperation->equal("REG_NO", i);
+ myNdbOperation->setValue("BRAND", "Mercedes");
+ myNdbOperation->setValue("COLOR", "Blue");
+ // Prepare transaction (the transaction is NOT yet sent to NDB)
+ myNdbConnection[i]->executeAsynchPrepare(Commit, &callback, NULL);
+ }
+
+
+ /**
+ * Five black bmw
+ */
+ for (int i = 5; i < 10; i++)
+ {
+ myNdbConnection[i] = myNdb->startTransaction();
+ if (myNdbConnection[i] == NULL)
+ APIERROR(myNdb->getNdbError());
+ myNdbOperation = myNdbConnection[i]->getNdbOperation("GARAGE");
+ // Error check. If error, then maybe table MYTABLENAME is not in database
+ if (myNdbOperation == NULL)
+ APIERROR(myNdbConnection[i]->getNdbError());
+ myNdbOperation->insertTuple();
+ myNdbOperation->equal("REG_NO", i);
+ myNdbOperation->setValue("BRAND", "BMW");
+ myNdbOperation->setValue("COLOR", "Black");
+ // Prepare transaction (the transaction is NOT yet sent to NDB)
+ myNdbConnection[i]->executeAsynchPrepare(Commit, &callback, NULL);
+ }
+
+ /**
+ * Five pink toyotas
+ */
+ for (int i = 10; i < 15; i++) {
+ myNdbConnection[i] = myNdb->startTransaction();
+ if (myNdbConnection[i] == NULL) APIERROR(myNdb->getNdbError());
+ myNdbOperation = myNdbConnection[i]->getNdbOperation("GARAGE");
+ // Error check. If error, then maybe table MYTABLENAME is not in database
+ if (myNdbOperation == NULL) APIERROR(myNdbConnection[i]->getNdbError());
+ myNdbOperation->insertTuple();
+ myNdbOperation->equal("REG_NO", i);
+ myNdbOperation->setValue("BRAND", "Toyota");
+ myNdbOperation->setValue("COLOR", "Pink");
+ // Prepare transaction (the transaction is NOT yet sent to NDB)
+ myNdbConnection[i]->executeAsynchPrepare(Commit, &callback, NULL);
+ }
+
+ // Send all transactions to NDB
+ myNdb->sendPreparedTransactions(0);
+ // Poll all transactions
+ myNdb->pollNdb(3000, 0);
+
+ // it is also possible to use sendPollNdb instead of
+ // myNdb->sendPreparedTransactions(0); and myNdb->pollNdb(3000, 15); above.
+ // myNdb->sendPollNdb(3000,0);
+ // Note! Neither sendPollNdb or pollNdb returs until all 15 callbacks have
+ // executed.
+
+ // Close all transactions. It is also possible to close transactions
+ // in the callback.
+ for (int i = 0; i < 15; i++)
+ myNdb->closeTransaction(myNdbConnection[i]);
+ return 1;
+}
+
+int scan_delete(Ndb* myNdb,
+ int parallelism,
+ int column,
+ int column_len,
+ 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;
+ NdbConnection *myTrans;
+ NdbScanOperation *myScanOp;
+
+ /**
+ * 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("GARAGE");
+ if (myScanOp == NULL)
+ {
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ return -1;
+ }
+
+ /**
+ * Define a result set for the scan.
+ */
+ NdbResultSet * rs = myScanOp->readTuplesExclusive(parallelism);
+ if( rs == 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.eq(column, color, column_len, false) <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(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 = rs->nextResult(true)) == 0){
+ do {
+ if (rs->deleteTuple() != 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 = rs->nextResult(false)) == 0);
+
+ /**
+ * Commit when all cached tuple have been marked for deletion
+ */
+ if(check != -1){
+ check = myTrans->execute(Commit);
+ myTrans->releaseCompletedOperations();
+ }
+ /**
+ * 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 parallelism,
+ int column_len,
+ int update_column,
+ const char * column_name,
+ 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;
+ NdbConnection *myTrans;
+ NdbScanOperation *myScanOp;
+
+ /**
+ * 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("GARAGE");
+ if (myScanOp == NULL)
+ {
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ return -1;
+ }
+
+ /**
+ * Define a result set for the scan.
+ */
+ NdbResultSet * rs = myScanOp->readTuplesExclusive(parallelism);
+ if( rs == 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.eq(update_column, before_color, column_len, false) <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(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;
+ }
+
+ /**
+ * Define an update operation
+ */
+ NdbOperation * myUpdateOp;
+ /**
+ * start of loop: nextResult(true) means that "parallelism" number of
+ * rows are fetched from NDB and cached in NDBAPI
+ */
+ while((check = rs->nextResult(true)) == 0){
+ do {
+ /**
+ * Get update operation
+ */
+ myUpdateOp = rs->updateTuple();
+ 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 = rs->nextResult(false)) == 0);
+
+ /**
+ * Commit when all cached tuple have been updated
+ */
+ if(check != -1){
+ check = myTrans->execute(Commit);
+ myTrans->releaseCompletedOperations();
+ }
+ /**
+ * 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_print(Ndb * myNdb, int parallelism,
+ int column_len_brand,
+ int column_len_color)
+{
+// Scan all records exclusive and update
+ // them one by one
+ int retryAttempt = 0;
+ const int retryMax = 10;
+ int fetchedRows = 0;
+ int check;
+ NdbError err;
+ NdbConnection *myTrans;
+ NdbScanOperation *myScanOp;
+ /* Result of reading attribute value, three columns:
+ REG_NO, BRAND, and COLOR
+ */
+ NdbRecAttr * myRecAttr[3];
+
+ /**
+ * 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("GARAGE");
+ if (myScanOp == NULL)
+ {
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ return -1;
+ }
+
+ /**
+ * Define a result set for the scan.
+ */
+ NdbResultSet * rs = myScanOp->readTuplesExclusive(parallelism);
+ if( rs == 0 ) {
+ 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(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 = rs->nextResult(true)) == 0){
+ do {
+
+ fetchedRows++;
+ /**
+ * print REG_NO unsigned int
+ */
+ std::cout << myRecAttr[0]->u_32_value() << "\t";
+ char * buf_brand = new char[column_len_brand+1];
+ char * buf_color = new char[column_len_color+1];
+ /**
+ * print BRAND character string
+ */
+ memcpy(buf_brand, myRecAttr[1]->aRef(), column_len_brand);
+ buf_brand[column_len_brand] = 0;
+ std::cout << buf_brand << "\t";
+ delete [] buf_brand;
+ /**
+ * print COLOR character string
+ */
+ memcpy(buf_color, myRecAttr[2]->aRef(), column_len_color);
+ buf_brand[column_len_color] = 0;
+ std::cout << buf_color << std::endl;
+ delete [] buf_color;
+ /**
+ * nextResult(false) means that the records
+ * cached in the NDBAPI are modified before
+ * fetching more rows from NDB.
+ */
+ } while((check = rs->nextResult(false)) == 0);
+
+ }
+ myNdb->closeTransaction(myTrans);
+ return 1;
+ }
+ return -1;
+
+}
+
+
+int main()
+{
+ Ndb* myNdb = new Ndb( "TEST_DB" ); // Object representing the database
+
+
+
+ /*******************************************
+ * Initialize NDB and wait until its ready *
+ *******************************************/
+ if (myNdb->init(1024) == -1) { // Set max 1024 parallel transactions
+ APIERROR(myNdb->getNdbError());
+ exit(-1);
+ }
+
+ if (myNdb->waitUntilReady(30) != 0) {
+ std::cout << "NDB was not ready within 30 secs." << std::endl;
+ exit(-1);
+ }
+ create_table(myNdb);
+
+ NdbDictionary::Dictionary* myDict = myNdb->getDictionary();
+ int column_color = myDict->getTable("GARAGE")->getColumn("COLOR")->getColumnNo();
+ int column_len_color =
+ myDict->getTable("GARAGE")->getColumn("COLOR")->getLength();
+ int column_len_brand =
+ myDict->getTable("GARAGE")->getColumn("BRAND")->getLength();
+ int parallelism = 16;
+
+
+ if(populate(myNdb) > 0)
+ std::cout << "populate: Success!" << std::endl;
+
+ if(scan_print(myNdb, parallelism, column_len_brand, column_len_color) > 0)
+ std::cout << "scan_print: Success!" << std::endl << std::endl;
+
+ std::cout << "Going to delete all pink cars!" << std::endl;
+ if(scan_delete(myNdb, parallelism, column_color,
+ column_len_color, "Pink") > 0)
+ std::cout << "scan_delete: Success!" << std::endl << std::endl;
+
+ if(scan_print(myNdb, parallelism, column_len_brand, column_len_color) > 0)
+ std::cout << "scan_print: Success!" << std::endl << std::endl;
+
+ std::cout << "Going to update all blue cars to black cars!" << std::endl;
+ if(scan_update(myNdb, parallelism, column_len_color, column_color,
+ "COLOR", "Blue", "Black") > 0)
+ {
+ std::cout << "scan_update: Success!" << std::endl << std::endl;
+ }
+ if(scan_print(myNdb, parallelism, column_len_brand, column_len_color) > 0)
+ std::cout << "scan_print: Success!" << std::endl << std::endl;
+
+ delete myNdb;
+}
+
diff --git a/ndb/examples/ndbapi_scan_example/readme.txt b/ndb/examples/ndbapi_scan_example/readme.txt
new file mode 100644
index 00000000000..47cb4bf9ffa
--- /dev/null
+++ b/ndb/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/ndb/examples/select_all/Makefile b/ndb/examples/select_all/Makefile
new file mode 100644
index 00000000000..2bec205fa99
--- /dev/null
+++ b/ndb/examples/select_all/Makefile
@@ -0,0 +1,33 @@
+-include .defs.mk
+#NDB_OS = OS_YOU_ARE_RUNNING_ON
+#You need to set the NDB_OS variable here
+TARGET = select_all
+SRCS = select_all.cpp
+OBJS = select_all.o
+CXX = g++
+CFLAGS = -c -Wall -fno-rtti -fno-exceptions
+DEBUG =
+LFLAGS = -Wall
+INCLUDE_DIR = ../../include
+LIB_DIR = ../../lib
+ifeq ($(NDB_OS), SOLARIS)
+# Here is the definition of system libraries necessary for Solaris 7
+SYS_LIB =
+endif
+ifeq ($(NDB_OS), LINUX)
+# Here is the definition of system libraries necessary for Linux 2.4
+SYS_LIB =
+endif
+ifeq ($(NDB_OS), MACOSX)
+# Here is the definition of system libraries necessary for Mac OS X
+SYS_LIB =
+endif
+
+$(TARGET): $(OBJS)
+ $(CXX) $(LFLAGS) -L$(LIB_DIR) $(OBJS) -lNDB_API $(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/ndb/examples/select_all/select_all.cpp b/ndb/examples/select_all/select_all.cpp
new file mode 100644
index 00000000000..3cdbdc47e62
--- /dev/null
+++ b/ndb/examples/select_all/select_all.cpp
@@ -0,0 +1,258 @@
+/* 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 */
+
+//
+// select_all.cpp: Prints all rows of a table
+//
+// Usage: select_all <table_name>+
+
+#include <NdbApi.hpp>
+
+// Used for cout
+#include <iostream>
+using namespace std;
+#include <stdio.h>
+#include <string.h>
+
+#define APIERROR(error) \
+ { cout << "Error in " << __FILE__ << ", line:" << __LINE__ << ", code:" \
+ << error.code << ", msg: " << error.message << "." << endl; \
+ exit(-1); }
+
+void usage(const char* prg) {
+ cout << "Usage: " << prg << " <table name>" << endl;
+ cout << "Prints all rows of table named <table name>" << endl;
+ exit(0);
+}
+
+/*****************************************************************************
+ *************************** Result Set Container ****************************
+ *****************************************************************************/
+
+/*
+ * Container of NdbRecAttr objects.
+ * (NdbRecAttr objects are database rows read by a scan operation.)
+ */
+class ResultSetContainer {
+public:
+ /**
+ * Initialize ResultSetContainer object for table named <tableName>
+ * - Allocates memory
+ * - Fetches attribute names from NDB Cluster
+ */
+ void init(NdbDictionary::Dictionary* dict, const char* tableName);
+
+ /**
+ * Get no of attributes for stored NdbRecAttr objects
+ */
+ int getNoOfAttributes() const;
+
+ /**
+ * Get NdbRecAttr object no i
+ */
+ NdbRecAttr* & getAttrStore(int i);
+
+ /**
+ * Get attribute name of attribute no i
+ */
+ const char* getAttrName(int i) const;
+
+ /**
+ * Print header of rows
+ */
+ void header() const;
+
+private:
+ int m_cols; // No of attributes for stored NdbRecAttr objects
+ char **m_names; // Names of attributes
+ NdbRecAttr **m_data; // The actual stored NdbRecAttr objects
+};
+
+void ResultSetContainer::init(NdbDictionary::Dictionary * dict,
+ const char* tableName)
+{
+ // Get Table object from NDB (this contains metadata about all tables)
+ const NdbDictionary::Table * tab = dict->getTable(tableName);
+
+ // Get table id of the table we are interested in
+ if (tab == 0) APIERROR(dict->getNdbError()); // E.g. table didn't exist
+
+ // Get no of attributes and allocate memory
+ m_cols = tab->getNoOfColumns();
+ m_names = new char* [m_cols];
+ m_data = new NdbRecAttr* [m_cols];
+
+ // Store all attribute names for the table
+ for (int i = 0; i < m_cols; i++) {
+ m_names[i] = new char[255];
+ snprintf(m_names[i], 255, "%s", tab->getColumn(i)->getName());
+ }
+}
+
+int ResultSetContainer::getNoOfAttributes() const {return m_cols;}
+NdbRecAttr*& ResultSetContainer::getAttrStore(int i) {return m_data[i];}
+const char* ResultSetContainer::getAttrName(int i) const {return m_names[i];}
+
+/*****************************************************************************
+ ********************************** MAIN ***********************************
+ *****************************************************************************/
+
+int main(int argc, const char** argv)
+{
+ Ndb* myNdb = new Ndb("ndbapi_example4"); // Object representing the database
+ NdbConnection* myNdbConnection; // For transactions
+ NdbOperation* myNdbOperation; // For operations
+ int check;
+
+ if (argc != 2) {
+ usage(argv[0]);
+ exit(0);
+ }
+ const char* tableName = argv[1];
+
+ /*******************************************
+ * Initialize NDB and wait until its ready *
+ *******************************************/
+ if (myNdb->init() == -1) {
+ APIERROR(myNdb->getNdbError());
+ exit(-1);
+ }
+
+ if (myNdb->waitUntilReady(30) != 0) {
+ cout << "NDB was not ready within 30 secs." << endl;
+ exit(-1);
+ }
+
+ /***************************
+ * Define and execute scan *
+ ***************************/
+ cout << "Select * from " << tableName << endl;
+
+ ResultSetContainer * container = new ResultSetContainer;
+ container->init(myNdb->getDictionary(), tableName);
+
+ myNdbConnection = myNdb->startTransaction();
+ if (myNdbConnection == NULL) APIERROR(myNdb->getNdbError());
+
+ myNdbOperation = myNdbConnection->getNdbOperation(tableName);
+ if (myNdbOperation == NULL) APIERROR(myNdbConnection->getNdbError());
+
+ // Define the operation to be an 'openScanRead' operation.
+ check = myNdbOperation->openScanRead(1);
+ if (check == -1) APIERROR(myNdbConnection->getNdbError());
+
+ // Set interpreted program to just be the single instruction
+ // 'interpret_exit_ok'. (This approves all rows of the table.)
+ if (myNdbOperation->interpret_exit_ok() == -1)
+ APIERROR(myNdbConnection->getNdbError());
+
+ // Get all attribute values of the row
+ for(int i = 0; i < container->getNoOfAttributes(); i++){
+ if((container->getAttrStore(i) =
+ myNdbOperation->getValue(container->getAttrName(i))) == 0)
+ APIERROR(myNdbConnection->getNdbError());
+ }
+
+ // Execute scan operation
+ check = myNdbConnection->executeScan();
+ if (check == -1) APIERROR(myNdbConnection->getNdbError());
+
+ /****************
+ * Print header *
+ ****************/
+ for (int i = 0; i < container->getNoOfAttributes(); i++)
+ cout << container->getAttrName(i) << "\t";
+
+ cout << endl;
+ for (int i = 0; i < container->getNoOfAttributes(); i++) {
+ for (int j = strlen(container->getAttrName(i)); j > 0; j--)
+ cout << "-";
+ cout << "\t";
+ }
+ cout << "\n";
+
+ /**************
+ * Scan table *
+ **************/
+ int eof;
+ int rows = 0;
+
+ // Print all rows of table
+ while ((eof = myNdbConnection->nextScanResult()) == 0) {
+ rows++;
+
+ for (int i = 0; i < container->getNoOfAttributes(); i++) {
+ if (container->getAttrStore(i)->isNULL()) {
+ cout << "NULL";
+ } else {
+
+ // Element size of value (No of bits per element in attribute value)
+ const int size = container->getAttrStore(i)->attrSize();
+
+ // No of elements in an array attribute (Is 1 if non-array attribute)
+ const int aSize = container->getAttrStore(i)->arraySize();
+
+ switch(container->getAttrStore(i)->attrType()){
+ case UnSigned:
+ switch(size) {
+ case 8: cout << container->getAttrStore(i)->u_64_value(); break;
+ case 4: cout << container->getAttrStore(i)->u_32_value(); break;
+ case 2: cout << container->getAttrStore(i)->u_short_value(); break;
+ case 1: cout << (unsigned) container->getAttrStore(i)->u_char_value();
+ break;
+ default: cout << "Unknown size" << endl;
+ }
+ break;
+
+ case Signed:
+ switch(size) {
+ case 8: cout << container->getAttrStore(i)->int64_value(); break;
+ case 4: cout << container->getAttrStore(i)->int32_value(); break;
+ case 2: cout << container->getAttrStore(i)->short_value(); break;
+ case 1: cout << (int) container->getAttrStore(i)->char_value(); break;
+ default: cout << "Unknown size" << endl;
+ }
+ break;
+
+ case String:
+ {
+ char* buf = new char[aSize+1];
+ memcpy(buf, container->getAttrStore(i)->aRef(), aSize);
+ buf[aSize] = 0;
+ cout << buf;
+ delete [] buf;
+ }
+ break;
+
+ case Float:
+ cout << container->getAttrStore(i)->float_value();
+ break;
+
+ default:
+ cout << "Unknown";
+ break;
+ }
+ }
+ cout << "\t";
+ }
+ cout << endl;
+ }
+ if (eof == -1) APIERROR(myNdbConnection->getNdbError());
+
+ myNdb->closeTransaction(myNdbConnection);
+
+ cout << "Selected " << rows << " rows." << endl;
+}