diff options
Diffstat (limited to 'ndb/test/ndbapi/ScanFunctions.hpp')
-rw-r--r-- | ndb/test/ndbapi/ScanFunctions.hpp | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/ndb/test/ndbapi/ScanFunctions.hpp b/ndb/test/ndbapi/ScanFunctions.hpp new file mode 100644 index 00000000000..36d01909861 --- /dev/null +++ b/ndb/test/ndbapi/ScanFunctions.hpp @@ -0,0 +1,392 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <NDBT.hpp> +#include <NDBT_Test.hpp> + + + +struct Attrib { + int numAttribs; + int attribs[1024]; +}; +class AttribList { +public: + AttribList(){}; + ~AttribList(){ + for(size_t i = 0; i < attriblist.size(); i++){ + delete attriblist[i]; + } + }; + void buildAttribList(const NdbDictionary::Table* pTab); + Vector<Attrib*> attriblist; +}; + + +// Functions that help out in testing that we may call +// scan functions in wrong order etc +// and receive a proper errormessage +class ScanFunctions { +public: + ScanFunctions(const NdbDictionary::Table& _tab) : tab(_tab){ + } + enum ActionType { + CloseWithoutStop, + NextScanWhenNoMore, + ExecuteScanWithOutOpenScan, + OnlyOneScanPerTrans, + OnlyOneOpBeforeOpenScan, + OnlyOpenScanOnce, + OnlyOneOpInScanTrans, + CheckInactivityTimeOut, + CheckInactivityBeforeClose , + NoCloseTransaction, + EqualAfterOpenScan + }; + + + int scanReadFunctions(Ndb* pNdb, + int records, + int parallelism, + ActionType action, + bool exclusive); +private: + const NdbDictionary::Table& tab; +}; + + +inline +int +ScanFunctions::scanReadFunctions(Ndb* pNdb, + int records, + int parallelism, + ActionType action, + bool exclusive){ + int retryAttempt = 0; + const int retryMax = 100; + int sleepTime = 10; + int check; + NdbConnection *pTrans; + NdbOperation *pOp; + + while (true){ + if (retryAttempt >= retryMax){ + g_err << "ERROR: has retried this operation " << retryAttempt + << " times, failing!" << endl; + return NDBT_FAILED; + } + + pTrans = pNdb->startTransaction(); + if (pTrans == NULL) { + const NdbError err = pNdb->getNdbError(); + if (err.status == NdbError::TemporaryError){ + ERR(err); + NdbSleep_MilliSleep(50); + retryAttempt++; + continue; + } + ERR(err); + return NDBT_FAILED; + } + + // Execute the scan without defining a scan operation + if(action != ExecuteScanWithOutOpenScan){ + + if (action == OnlyOneOpBeforeOpenScan){ + // There can only be one operation defined when calling openScan + NdbOperation* pOp3; + pOp3 = pTrans->getNdbOperation(tab.getName()); + if (pOp3 == NULL) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + } + + pOp = pTrans->getNdbOperation(tab.getName()); + if (pOp == NULL) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + if (exclusive == true) + check = pOp->openScanExclusive(parallelism); + else + check = pOp->openScanRead(parallelism); + if( check == -1 ) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + + if (action == OnlyOneScanPerTrans){ + // There can only be one operation in a scan transaction + NdbOperation* pOp4; + pOp4 = pTrans->getNdbOperation(tab.getName()); + if (pOp4 == NULL) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + } + + if (action == OnlyOpenScanOnce){ + // Call openScan one more time when it's already defined + check = pOp->openScanRead(parallelism); + if( check == -1 ) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + } + + if (action == OnlyOneOpInScanTrans){ + // Try to add another op to this scanTransaction + NdbOperation* pOp2; + pOp2 = pTrans->getNdbOperation(tab.getName()); + if (pOp2 == NULL) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + } + + + if (action==EqualAfterOpenScan){ + check = pOp->equal(tab.getColumn(0)->getName(), 10); + if( check == -1 ) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + } + + check = pOp->interpret_exit_ok(); + if( check == -1 ) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + for(int a = 0; a<tab.getNoOfColumns(); a++){ + if(pOp->getValue(tab.getColumn(a)->getName()) == NULL) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + } + } + check = pTrans->executeScan(); + if( check == -1 ) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + + int abortCount = records / 10; + bool abortTrans = (action==CloseWithoutStop); + int eof; + int rows = 0; + eof = pTrans->nextScanResult(); + + while(eof == 0){ + rows++; + + if (abortCount == rows && abortTrans == true){ + g_info << "Scan is aborted after "<<abortCount<<" rows" << endl; + + if (action != CloseWithoutStop){ + // Test that we can closeTrans without stopScan + check = pTrans->stopScan(); + if( check == -1 ) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + } + + + pNdb->closeTransaction(pTrans); + return NDBT_OK; + } + + if(action == CheckInactivityTimeOut){ + if ((rows % (records / 10)) == 0){ + // Sleep for a long time before calling nextScanResult + if (sleepTime > 1) + sleepTime--; + g_info << "Sleeping "<<sleepTime<<" secs " << endl; + NdbSleep_SecSleep(sleepTime); + } + } + + eof = pTrans->nextScanResult(); + } + if (eof == -1) { + const NdbError err = pTrans->getNdbError(); + + if (err.status == NdbError::TemporaryError){ + ERR(err); + + // Be cruel, call nextScanResult after error + for(int i=0; i<10; i++){ + eof =pTrans->nextScanResult(); + if(eof == 0){ + g_err << "nextScanResult returned eof = " << eof << endl + << " That is an error when there are no more records" << endl; + return NDBT_FAILED; + } + } + // Be cruel end + + pNdb->closeTransaction(pTrans); + NdbSleep_MilliSleep(50); + retryAttempt++; + g_info << "Starting over" << endl; + + // If test is CheckInactivityTimeOut + // error 296 is expected + if ((action == CheckInactivityTimeOut) && + (err.code == 296)) + return NDBT_OK; + + continue; + } + ERR(err); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + if (action == NextScanWhenNoMore){ + g_info << "Calling nextScanresult when there are no more records" << endl; + for(int i=0; i<10; i++){ + eof =pTrans->nextScanResult(); + if(eof == 0){ + g_err << "nextScanResult returned eof = " << eof << endl + << " That is an error when there are no more records" << endl; + return NDBT_FAILED; + } + } + + } + if(action ==CheckInactivityBeforeClose){ + // Sleep for a long time before calling close + g_info << "NdbSleep_SecSleep(5) before close transaction" << endl; + NdbSleep_SecSleep(5); + } + if(action == NoCloseTransaction) + g_info << "Forgetting to close transaction" << endl; + else + pNdb->closeTransaction(pTrans); + + g_info << rows << " rows have been read" << endl; + if (records != 0 && rows != records){ + g_err << "Check expected number of records failed" << endl + << " expected=" << records <<", " << endl + << " read=" << rows << endl; + return NDBT_FAILED; + } + + return NDBT_OK; + } + return NDBT_FAILED; + + +} + +void AttribList::buildAttribList(const NdbDictionary::Table* pTab){ + attriblist.clear(); + + Attrib* attr; + // Build attrib definitions that describes which attributes to read + // Try to build strange combinations, not just "all" or all PK's + + // Scan without reading any attributes + attr = new Attrib; + attr->numAttribs = 0; + attriblist.push_back(attr); + + for(int i = 1; i < pTab->getNoOfColumns(); i++){ + attr = new Attrib; + attr->numAttribs = i; + for(int a = 0; a<i; a++) + attr->attribs[a] = a; + attriblist.push_back(attr); + } + for(int i = pTab->getNoOfColumns()-1; i > 0; i--){ + attr = new Attrib; + attr->numAttribs = i; + for(int a = 0; a<i; a++) + attr->attribs[a] = a; + attriblist.push_back(attr); + } + for(int i = pTab->getNoOfColumns(); i > 0; i--){ + attr = new Attrib; + attr->numAttribs = pTab->getNoOfColumns() - i; + for(int a = 0; a<pTab->getNoOfColumns() - i; a++) + attr->attribs[a] = pTab->getNoOfColumns()-a-1; + attriblist.push_back(attr); + } + for(int i = 1; i < pTab->getNoOfColumns(); i++){ + attr = new Attrib; + attr->numAttribs = pTab->getNoOfColumns() - i; + for(int a = 0; a<pTab->getNoOfColumns() - i; a++) + attr->attribs[a] = pTab->getNoOfColumns()-a-1; + attriblist.push_back(attr); + } + for(int i = 1; i < pTab->getNoOfColumns(); i++){ + attr = new Attrib; + attr->numAttribs = 2; + for(int a = 0; a<2; a++){ + attr->attribs[a] = i%pTab->getNoOfColumns(); + } + attriblist.push_back(attr); + } + + // Last + attr = new Attrib; + attr->numAttribs = 1; + attr->attribs[0] = pTab->getNoOfColumns()-1; + attriblist.push_back(attr); + + // Last and first + attr = new Attrib; + attr->numAttribs = 2; + attr->attribs[0] = pTab->getNoOfColumns()-1; + attr->attribs[1] = 0; + attriblist.push_back(attr); + + // First and last + attr = new Attrib; + attr->numAttribs = 2; + attr->attribs[0] = 0; + attr->attribs[1] = pTab->getNoOfColumns()-1; + attriblist.push_back(attr); + +#if 1 + for(size_t i = 0; i < attriblist.size(); i++){ + + g_info << attriblist[i]->numAttribs << ": " ; + for(int a = 0; a < attriblist[i]->numAttribs; a++) + g_info << attriblist[i]->attribs[a] << ", "; + g_info << endl; + } +#endif + +} |