summaryrefslogtreecommitdiffstats
path: root/qlparser/qtjoiniterator.cc
diff options
context:
space:
mode:
Diffstat (limited to 'qlparser/qtjoiniterator.cc')
-rw-r--r--qlparser/qtjoiniterator.cc338
1 files changed, 338 insertions, 0 deletions
diff --git a/qlparser/qtjoiniterator.cc b/qlparser/qtjoiniterator.cc
new file mode 100644
index 0000000..12277ab
--- /dev/null
+++ b/qlparser/qtjoiniterator.cc
@@ -0,0 +1,338 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+#include "raslib/rmdebug.hh"
+
+#include "qlparser/qtjoiniterator.hh"
+#include "qlparser/qtmdd.hh"
+
+#include <iostream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+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<QtData*>::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; tupelPos<actualTupel->size(); 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; tupelPos<actualTupel->size(); 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;
+}