/* * This file is part of rasdaman community. * * Rasdaman community 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 3 of the License, or * (at your option) any later version. * * Rasdaman community 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 rasdaman community. If not, see . * * Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / rasdaman GmbH. * * For more information please see * or contact Peter Baumann via . */ /************************************************************* * * * PURPOSE: * * * COMMENTS: * ************************************************************/ #include "raslib/rmdebug.hh" #include "qlparser/qtjoiniterator.hh" #include "qlparser/qtmdd.hh" #include #ifndef CPPSTDLIB #include // STL #else #include using namespace std; #endif const QtNode::QtNodeType QtJoinIterator::nodeType = QtNode::QT_JOIN_ITERATOR; QtJoinIterator::QtJoinIterator() : QtIterator(), actualTupel(NULL), outputStreamIsEmpty(false) { } QtJoinIterator::QtJoinIterator( QtNode* node ) : QtIterator( node ), actualTupel(NULL), outputStreamIsEmpty(false) { } QtJoinIterator::~QtJoinIterator() { vector::iterator i; //default if( actualTupel ) { // first delete still existing data carriers for( QtDataList::iterator iter=actualTupel->begin(); iter!=actualTupel->end(); iter++ ) if( *iter ) (*iter)->deleteRef(); delete actualTupel; actualTupel=NULL; } } void QtJoinIterator::printTree( int tab, ostream& s, QtChildType mode ) { s << SPACE_STR(tab).c_str() << "QtJoinIterator Object: type " << flush; dataStreamType.printStatus( s ); s << endl; QtIterator::printTree( tab, s, mode ); } void QtJoinIterator::printAlgebraicExpression( ostream& s ) { s << "join"; QtIterator::printAlgebraicExpression( s ); } void QtJoinIterator::open() { RMDBCLASS( "QtJoinIterator", "open()", "qlparser", __FILE__, __LINE__ ) QtIterator::open(); outputStreamIsEmpty = false; // initialization if( inputs ) { // The idea of actualTupel initialization: // // tupel[0] tupel[1] tupel[2] ... | // ----------------------------------------------------- // 0 0 0 | initial phase // 0 b1 c1 | open // a1 b1 c1 | next invocation // a2 b1 c1 | " // a1 b2 c1 | " // : : : | " // allocate an empty tupel, right now each input stream provides one data element actualTupel = new QtDataList( inputs->size() ); // set the first element of the tupel to NULL (*actualTupel)[0] = NULL; // fill the tupel, except of the first element, with the first elements of the input streams //the first element is filled in the ::next() method for( int tupelPos=1; tupelPossize(); tupelPos++ ) { QtDataList* resultList = (*inputs)[tupelPos]->next(); if( resultList ) { // take the first data element of the input stream result (*actualTupel)[tupelPos] = (*resultList)[0]; // delete the result vector (only the first data carriers is taken, the others are never deleted) delete resultList; resultList = NULL; } else { // In that case, one of the input streams is empty. Therefore, the output stream of // the self object is empty either. (*actualTupel)[tupelPos] = NULL; outputStreamIsEmpty = true; } } // Reset the first stream again, because the first tupel element is catched when next() is // called for the first time. // (*inputs)[0]->reset(); } } QtNode::QtDataList* QtJoinIterator::next() { RMDBCLASS( "QtJoinIterator", "next()", "qlparser", __FILE__, __LINE__ ) QtDataList* returnValue = NULL; if( inputs && actualTupel && !outputStreamIsEmpty ) { bool nextTupelAvailable = true; bool nextTupelValid = false; int tupelPos; QtDataList* resultList = NULL; QtONCStreamList::iterator iter; while( !nextTupelValid && nextTupelAvailable && !outputStreamIsEmpty ) { // switch to the next tupel which means nextTupelAvailable = false; tupelPos = 0; iter = inputs->begin(); while( !nextTupelAvailable && iter!=inputs->end() ) { resultList = (*iter)->next(); // Test, if the first input stream is empty, because this is not tested in open() if( resultList == NULL && tupelPos==0 && (*actualTupel)[0] == 0 ) outputStreamIsEmpty = true; if( resultList == NULL ) { (*iter)->reset(); // reset the stream ... //this causes the first element of the list to be deleted - not the others resultList = (*iter)->next(); // ... and read the first element again // this was commented out because it will cause problems when the stream is closed // if it is commented out it will break join queries } else nextTupelAvailable = true; // // exchange the actual element in the tupel // // delete the data carrier if( (*actualTupel)[tupelPos] ) { (*actualTupel)[tupelPos]->deleteRef(); (*actualTupel)[tupelPos] = NULL; } if( resultList ) { // take the first data element of the input stream result - copy the data carrier pointer (*actualTupel)[tupelPos] = (*resultList)[0]; // delete the result vector (only the first data carrier is taken, the others are never deleted) delete resultList; resultList = NULL; } iter++; tupelPos++; } if( nextTupelAvailable ) nextTupelValid = true; } if( nextTupelAvailable ) { // Copy the actual tupel in order to pass it as the next stream element // which means increase references to data elements. returnValue = new QtDataList( actualTupel->size() ); for( tupelPos=0; tupelPos < actualTupel->size(); tupelPos++ ) if( (*actualTupel)[tupelPos] ) { (*returnValue)[tupelPos] = (*actualTupel)[tupelPos]; (*actualTupel)[tupelPos]->incRef(); } else { // should not come here, because now the next tupel isn't valid // delete return value again for( tupelPos=0; tupelPos < returnValue->size(); tupelPos++ ) if( (*returnValue)[tupelPos] ) (*returnValue)[tupelPos]->deleteRef(); delete returnValue; returnValue = NULL; RMInit::logOut << "Internal Error in QtJoinIterator::next()" << endl; } } } return returnValue; } void QtJoinIterator::close() { RMDBCLASS( "QtJoinIterator", "close()", "qlparser", __FILE__, __LINE__ ) if( actualTupel ) { // first delete still existing data carriers for( QtDataList::iterator iter=actualTupel->begin(); iter!=actualTupel->end(); iter++ ) if( *iter ) (*iter)->deleteRef(); delete actualTupel; actualTupel = NULL; } QtIterator::close(); } void QtJoinIterator::reset() { RMDBCLASS( "QtJoinIterator", "reset()", "qlparser", __FILE__, __LINE__ ) // reset the input streams QtIterator::reset(); if( inputs ) { // first delete still existing data carriers for( QtDataList::iterator iter=actualTupel->begin(); iter!=actualTupel->end(); iter++ ) if( *iter ) { (*iter)->deleteRef(); (*iter) = NULL; } // fill the tupel with the first elements of the input streams except of the first element for( int tupelPos=1; tupelPossize(); tupelPos++ ) { QtDataList* resultList = (*inputs)[tupelPos]->next(); if( resultList ) { // take the first data element of the input stream result (*actualTupel)[tupelPos] = (*resultList)[0]; // delete the result vector (only the first data carriers is taken, the others are never deleted) delete resultList; resultList = NULL; } else (*actualTupel)[tupelPos] = NULL; } (*actualTupel)[0] = NULL; // fist tupel element is catched when next() is called for the first time } } const QtTypeTuple& QtJoinIterator::checkType() { RMDBCLASS( "QtJoinIterator", "checkType()", "qlparser", __FILE__, __LINE__ ) getInputTypeTuple( dataStreamType ); return dataStreamType; }