summaryrefslogtreecommitdiff
path: root/ndb/test/ndbapi/ScanFunctions.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'ndb/test/ndbapi/ScanFunctions.hpp')
-rw-r--r--ndb/test/ndbapi/ScanFunctions.hpp392
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
+
+}