diff options
author | unknown <magnus@neptunus.(none)> | 2004-04-14 10:53:21 +0200 |
---|---|---|
committer | unknown <magnus@neptunus.(none)> | 2004-04-14 10:53:21 +0200 |
commit | 6386c55cee50bad6a9979d1fab28e03bb8612ca7 (patch) | |
tree | 3fbbacf704304b69228474b9f03549ccd585a017 /ndb/examples | |
parent | 0ba6cb48d84f1ff951d09871a96be6cdef3f2c3c (diff) | |
download | mariadb-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')
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 Binary files differnew file mode 100644 index 00000000000..d8cae90ec5b --- /dev/null +++ b/ndb/examples/configurations/demos.tar 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; +} |