summaryrefslogtreecommitdiffstats
path: root/qlparser/qtbinaryfunc.cc
diff options
context:
space:
mode:
Diffstat (limited to 'qlparser/qtbinaryfunc.cc')
-rw-r--r--qlparser/qtbinaryfunc.cc1174
1 files changed, 1174 insertions, 0 deletions
diff --git a/qlparser/qtbinaryfunc.cc b/qlparser/qtbinaryfunc.cc
new file mode 100644
index 0000000..9b77888
--- /dev/null
+++ b/qlparser/qtbinaryfunc.cc
@@ -0,0 +1,1174 @@
+/*
+* 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:
+ * - QtScale is expected to have rounding errors with >1 tiles
+ * - shift, extend, scale release input tiles only at end; this
+ * shouldbe optimized (release immediately after evaluating)
+ * - why is this file called "binary"? all ops have just one MDD!
+ * - QtShift(), QtExtend() deliver for >1 tiles under PG an error
+ * "libpq 'select' did not yield 1 result but 0"
+ * which however does not seem to affect the result.
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtMintervalSelect, QtShift: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtbinaryfunc.cc,v 1.37 2005/09/03 20:17:55 rasdev Exp $";
+
+#include "mymalloc/mymalloc.h"
+
+#include "mymalloc/mymalloc.h"
+
+#include "qlparser/qtbinaryfunc.hh"
+#include "qlparser/qtdata.hh"
+#include "qlparser/qtintervaldata.hh"
+#include "qlparser/qtmintervaldata.hh"
+#include "qlparser/qtatomicdata.hh"
+#include "qlparser/qtmdd.hh"
+#include "qlparser/qtpointdata.hh"
+
+#include "mddmgr/mddobj.hh"
+#include "tilemgr/tile.hh"
+
+#include "raslib/rmdebug.hh"
+#include "raslib/dlist.hh"
+
+#include <iostream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+using namespace std;
+#endif
+
+
+// --- QtShift --------------------------------------------------
+
+const QtNode::QtNodeType QtShift::nodeType = QT_SHIFT;
+
+QtShift::QtShift( QtOperation* mddOp, QtOperation* pointOp )
+ : QtBinaryOperation( mddOp, pointOp )
+{
+}
+
+
+
+bool
+QtShift::isCommutative() const
+{
+ return false; // NOT commutative
+}
+
+
+
+QtData*
+QtShift::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtShift", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+ QtData* operand1 = NULL;
+ QtData* operand2 = NULL;
+
+ // evaluate sub-nodes to obtain operand values
+ if( getOperands( inputList, operand1, operand2 ) )
+ {
+ //
+ // This implementation simply creates a new transient MDD object with the new
+ // domain while copying the data. Optimization of this is left for future work.
+ //
+
+ QtMDD* qtMDDObj = (QtMDD*)operand1;
+ const r_Point& transPoint = ((QtPointData*)operand2)->getPointData();
+ MDDObj* currentMDDObj = qtMDDObj->getMDDObject();
+
+ if( transPoint.dimension() != qtMDDObj->getLoadDomain().dimension() )
+ {
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ RMInit::logOut << "Error: QtShift::evaluate( QtDataList* ) - dimensionality of MDD and point expression do not match." << endl;
+ parseInfo.setErrorNo(407);
+ throw parseInfo;
+ }
+
+ // compute new domain
+ r_Minterval destinationDomain( qtMDDObj->getLoadDomain().create_translation( transPoint ) );
+
+ // create a transient MDD object for the query result
+ MDDObj* resultMDD = new MDDObj( currentMDDObj->getMDDBaseType(), destinationDomain );
+
+ // get all tiles
+ vector<Tile* >* tiles = currentMDDObj->intersect( qtMDDObj->getLoadDomain() );
+
+ // iterate over source tiles
+ for( vector<Tile*>::iterator tileIter = tiles->begin(); tileIter != tiles->end(); tileIter++ )
+ {
+ // get relevant area of source tile
+ r_Minterval sourceTileDomain = qtMDDObj->getLoadDomain().create_intersection( (*tileIter)->getDomain() );
+
+ // compute translated tile domain
+ r_Minterval destinationTileDomain = sourceTileDomain.create_translation( transPoint );
+
+ // create a new transient tile, copy the transient data, and insert it into the mdd object
+ // FIXME: how can this work without tile area allocation??? -- PB 2005-jun-19
+ Tile* newTransTile = new Tile( destinationTileDomain, currentMDDObj->getCellType() );
+ newTransTile->copyTile( destinationTileDomain, *tileIter, sourceTileDomain );
+ resultMDD->insertTile( newTransTile );
+ }
+
+ // create a new QtMDD object as carrier object for the transient MDD object
+ returnValue = new QtMDD( (MDDObj*)resultMDD );
+
+ // delete the tile vector, the tiles itself are deleted when the destructor
+ // of the MDD object is called
+ delete tiles;
+ tiles=NULL;
+
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+ }
+
+ return returnValue;
+}
+
+
+
+void
+QtShift::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtShift Object " << getNodeType() << endl;
+
+ QtBinaryOperation::printTree( tab, s, mode );
+}
+
+
+
+void
+QtShift::printAlgebraicExpression( ostream& s )
+{
+ s << "shift(";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ",";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+void
+QtShift::optimizeLoad( QtTrimList* trimList )
+{
+ RMDBCLASS( "QtShift", "optimizeLoad( QtTrimList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtNode::QtTrimList *list1=NULL, *list2=NULL;
+
+ if( input1 && input2 )
+ {
+ QtNode::QtTrimList::iterator iter;
+
+ //
+ // The result of input2 has to be a constant expression.
+ //
+
+ // shift of trimList is just possible, if no open bounds are available
+ bool openBounds = false;
+ for( iter=trimList->begin(); iter!=trimList->end() && !openBounds; iter++ )
+ openBounds = !((*iter)->interval.is_low_fixed()) || !((*iter)->interval.is_high_fixed());
+
+ if( openBounds )
+ {
+ // release( trimList->begin(), trimList->end() );
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+
+ RMInit::logOut << "Error: QtShift::optimizeLoad() - spatial domain shift of open bounds is not supported" << endl;
+ parseInfo.setErrorNo(409);
+ throw parseInfo;
+ }
+
+ QtData* operand = input2->evaluate(NULL);
+
+ if( !operand )
+ {
+ // release( trimList->begin(), trimList->end() );
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+
+ RMInit::logOut << "Error: QtShift::optimizeLoad() - second operand of shift function must be a constant expression." << endl;
+ parseInfo.setErrorNo(408);
+ throw parseInfo;
+ }
+
+ if( operand->getDataType() != QT_POINT )
+ {
+ // release( trimList->begin(), trimList->end() );
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+
+ operand->deleteRef();
+
+ RMInit::logOut << "Error: QtShift::optimizeLoad() - second operand must be of type Point." << endl;
+ parseInfo.setErrorNo(406);
+ throw parseInfo;
+ }
+
+ // get transPoint
+ const r_Point& transPoint = ((QtPointData*)operand)->getPointData();
+
+ // shift trim elements by -transPoint
+ for( iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ QtTrimElement* elem = *iter;
+
+ if( elem->dimension <= transPoint.dimension() )
+ elem->interval.set_interval( elem->interval.low() - transPoint[elem->dimension], elem->interval.high() - transPoint[elem->dimension] );
+ }
+
+ // point is not needed anymore
+ operand->deleteRef();
+
+ input1->optimizeLoad( trimList );
+ }
+ else
+ {
+ // release( trimList->begin(), trimList->end() );
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+ }
+}
+
+
+
+const QtTypeElement&
+QtShift::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtShift", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ // check operand branches
+ if( input1 && input2 )
+ {
+
+ // get input types
+ const QtTypeElement& inputType1 = input1->checkType( typeTuple );
+ const QtTypeElement& inputType2 = input2->checkType( typeTuple );
+
+ if( inputType1.getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Error: QtShift::checkType() - first operand must be of type MDD." << endl;
+ parseInfo.setErrorNo(405);
+ throw parseInfo;
+ }
+
+ if( inputType2.getDataType() != QT_POINT )
+ {
+ RMInit::logOut << "Error: QtShift::checkType() - second operand must be of type Point." << endl;
+ parseInfo.setErrorNo(406);
+ throw parseInfo;
+ }
+
+ // pass MDD type
+ dataStreamType = inputType1;
+ }
+ else
+ RMInit::logOut << "Error: QtShift::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+
+// --- QtExtend --------------------------------------------------
+
+const QtNode::QtNodeType QtExtend::nodeType = QT_EXTEND;
+
+QtExtend::QtExtend( QtOperation* mddOp, QtOperation* mintervalOp )
+ : QtBinaryOperation( mddOp, mintervalOp )
+{
+}
+
+
+
+bool
+QtExtend::isCommutative() const
+{
+ return false; // NOT commutative
+}
+
+
+
+QtData*
+QtExtend::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtExtend", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL; // operation result
+ QtData* operand1 = NULL; // 1st operand: MDD expression
+ QtData* operand2 = NULL; // 2nd operand: Minterval expression
+ vector<Tile*> completeAreaList; // list of tiles comprising the whole area (possibly with holes); needed for 1-code below
+
+ if( getOperands( inputList, operand1, operand2 ) )
+ {
+ //
+ // This implementation simply creates a single new transient MDD object with the new
+ // domain while copying the data.
+ // FIXME: create a tiled object
+ //
+
+ QtMDD* qtMDDObj = (QtMDD*)operand1; // object to be extended
+ r_Minterval targetDomain = ((QtMintervalData*)operand2)->getMintervalData(); // new domain of extended object
+ MDDObj* currentMDDObj = qtMDDObj->getMDDObject();
+
+ // precondition checks (we call the MDD C and the Minterval M):
+ // - dim(C) == dim(M)
+ if( targetDomain.dimension() != qtMDDObj->getLoadDomain().dimension() )
+ {
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ RMInit::logOut << "Error: QtExtend::evaluate( QtDataList* ) - dimensionality of MDD and point expression do not match." << endl;
+ parseInfo.setErrorNo(407);
+ throw parseInfo;
+ }
+
+ // - M does not contain open bounds (i.e., "*")
+ if( ! targetDomain.is_origin_fixed() || ! targetDomain.is_high_fixed() )
+ {
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ RMInit::logOut << "Error: QtExtend::evaluate( QtDataList* ) - target domain must not have open bounds." << endl;
+ parseInfo.setErrorNo(420);
+ throw parseInfo;
+ }
+ // - M.subset( sdom(C) ); can we relieve this?
+ if( ! targetDomain.covers( qtMDDObj->getLoadDomain() ) )
+ {
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ RMInit::logOut << "Error: QtExtend::evaluate( QtDataList* ) - new interval does not cover MDD to be extended." << endl;
+ parseInfo.setErrorNo(421);
+ throw parseInfo;
+ }
+
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ) - extending MDD with basetype " << currentMDDObj->getMDDBaseType() << " and load domain " << qtMDDObj->getLoadDomain() << " to domain " << targetDomain << endl;
+
+ // create a transient MDD object for the query result
+ MDDObj* resultMDD = new MDDObj( currentMDDObj->getMDDBaseType(), targetDomain );
+
+ // --- 1: put all existing tiles into their place ------------------------
+
+ // get all tiles
+ vector<Tile* >* tiles = currentMDDObj->intersect( qtMDDObj->getLoadDomain() );
+
+ // iterate over source tiles
+ // Note that source and target MDD have the same coordinate basis
+ for( vector<Tile*>::iterator tileIter = tiles->begin(); tileIter != tiles->end(); tileIter++ )
+ {
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ) - load domain is " << qtMDDObj->getLoadDomain() << endl;
+ // get relevant area of source tile
+ r_Minterval sourceTileDomain = qtMDDObj->getLoadDomain().create_intersection( (*tileIter)->getDomain() );
+
+ Tile* newTransTile = new Tile( sourceTileDomain, currentMDDObj->getCellType() );
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ) - adding source part " << sourceTileDomain << " of tile " << (*tileIter)->getDomain() << endl;
+ newTransTile->copyTile( sourceTileDomain, *tileIter, sourceTileDomain );
+
+ resultMDD->insertTile( newTransTile ); // needed for 2-code below
+ // completeAreaList.push_back( newTransTile ); // needed for 1-code below
+ }
+
+ // --- 2: fill up new space with null values -----------------------------
+
+#if 0 // this 1-code does the same thing as the 2-code, but easier & more efficiently -- PB 2005-jun-24
+ // INCOMPLETE!
+ // create minimal (1x1) tiles at origin and high end, but only if the source domain isn't there
+ if (targetDomain.get_origin() != qtMDDObj->getLoadDomain().get_origin())
+ {
+ RMInit::logOut << "QtExtend::evaluate( QtDataList* ) - adding aux tile at origin." << endl;
+-> Tile* originTile = new Tile( origin..origin+1 , currentMDDObj->getCellType() );
+ extendDomainList.push_back( originTile );
+ }
+ if (targetDomain.get_high() != qtMDDObj->getLoadDomain().get_high())
+ {
+ RMInit::logOut << "QtExtend::evaluate( QtDataList* ) - adding aux tile at high." << endl;
+-> Tile* highTile = new Tile( high-1..high, currentMDDObj->getCellType() );
+ extendDomainList.push_back( highTile );
+ }
+
+ // merge all tiles into one & free not-used-any-longer stuff
+ Tile* completeTile = new Tile( extendDomainList );
+ delete[] extendDomainList;
+ resultMDD->insertTile( completeTile );
+ delete completeTile;
+
+#else // 2-code; unused -- PB 2005-jun-24
+ // the part below does the trick explicitly, leading to a larger number of result tiles.
+ // establish list of domains
+ vector<r_Minterval> extendDomainList;
+
+ // inspect 2*d lower/upper neighbours
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ): - inspect 2*d lower/upper neighbours, dimension is " << targetDomain.dimension() << endl;
+ for (r_Dimension d=0; d<targetDomain.dimension(); d++)
+ {
+ // is there any space left of original MDD; ie, has MDD been extended left?
+ if (targetDomain.get_origin()[d] < qtMDDObj->getLoadDomain().get_origin()[d])
+ {
+ // this domain is identical to original MDD except for dim d where it is left of original
+ r_Minterval lowerNeighbour = qtMDDObj->getLoadDomain();
+ lowerNeighbour[d] = r_Sinterval( targetDomain.get_origin()[d], qtMDDObj->getLoadDomain().get_origin()[d]-1 );
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ): adding lower neighbour domain " << lowerNeighbour << endl;
+ extendDomainList.push_back( lowerNeighbour );
+ }
+ // is there any space right of original MDD; ie, has MDD been extended right?
+ if (targetDomain.get_high()[d] > qtMDDObj->getLoadDomain().get_high()[d])
+ {
+ // this domain is identical to original MDD except for dim d where it is right of original
+ r_Minterval upperNeighbour = qtMDDObj->getLoadDomain();
+ upperNeighbour[d] =r_Sinterval( qtMDDObj->getLoadDomain().get_high()[d]+1, targetDomain.get_high()[d] );
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ): adding upper neighbour domain " << upperNeighbour << endl;
+ extendDomainList.push_back( upperNeighbour );
+ }
+ }
+
+ // inspect 2^d corner points
+
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ): - inspect 2^d corner neighbours, dimension is " << targetDomain.dimension() << endl;
+ r_Minterval cornerBoxDomain = r_Minterval( targetDomain.dimension() );
+ QtExtend::extendGetCornerTiles( targetDomain, qtMDDObj->getLoadDomain(), 0, targetDomain.dimension(), cornerBoxDomain, &extendDomainList );
+
+ // merge where possible to minimize tile number
+ // ...just an optimization, tbd later
+
+ // create tiles for all domains found
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ): - creating " << extendDomainList.size() << " tiles..." << endl;
+ for( vector<r_Minterval>::iterator domainIter = extendDomainList.begin(); domainIter != extendDomainList.end(); domainIter++ )
+ {
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ): creating tile for domain " << (*domainIter) << endl;
+ Tile* newTransTile = new Tile( *domainIter, currentMDDObj->getCellType() );
+ resultMDD->insertTile( newTransTile );
+ }
+#endif 0
+
+ // --- 3: package into MDD object & finalize -----------------------------
+
+ // create a new QtMDD object as carrier object for the transient MDD object
+ returnValue = new QtMDD( (MDDObj*)resultMDD );
+
+ // delete the tile vector, the tiles itself are deleted when the destructor
+ // of the MDD object is called
+
+ delete tiles;
+ tiles=NULL;
+
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ // temporary: dump result tile
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ) - result tile = " << newTransTile->printStatus() << endl;
+ // newTransTile->printStatus(99,RMInit::logOut);
+ }
+
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ) - done." << endl;
+ return returnValue;
+}
+
+#if 1 // needed for 1-code above -- PB 2005-jun-24
+/**
+aux function for QtExtend::evaluate(): build up (recursing the dimension) a list of all spatial domains that sit in the corners between outerDomain and innerDomain; at the recursion bottom the resulting domain is added to the cornerList.
+**/
+
+void
+QtExtend::extendGetCornerTiles( r_Minterval outerDomain, r_Minterval innerDomain, const r_Dimension currentDim, const r_Dimension maxDim, r_Minterval currentInterval, vector<r_Minterval>* cornerList )
+{
+ // RMInit::logOut << "QtExtend::extendGetCornerTiles( " << outerDomain << ", " << innerDomain << ", " << currentDim << ", " << maxDim << ", " << currentInterval << ", _ ) start" << endl;
+
+ // not yet addressed all dimensions in the current coordinate?
+// note: what about 1D? 0D?
+ if (currentDim < maxDim)
+ {
+ // add domain's lower end, continue building up the minterval
+ // ...but only if the area is nonempty
+ if (outerDomain.get_origin()[currentDim] < innerDomain.get_origin()[currentDim])
+ {
+ // make local working copy
+ r_Minterval extendedInterval( currentInterval );
+ // add i-th coordinate to domain, up to (but excluding) innerDomain
+ extendedInterval[currentDim] = r_Sinterval( outerDomain.get_origin()[currentDim], innerDomain.get_origin()[currentDim]-1 );
+ // inspect next dimension
+ // RMInit::logOut << "QtExtend::extendGetCornerTiles(): recursing for lower end box in next dimension " << currentDim+1 << " using extendedInterval " << extendedInterval << endl;
+ extendGetCornerTiles( outerDomain, innerDomain, currentDim+1, maxDim, extendedInterval, cornerList );
+ }
+ // add domain's upper end, continue building up the minterval
+ if (innerDomain.get_high()[currentDim] < outerDomain.get_high()[currentDim])
+ {
+ // make local working copy
+ r_Minterval extendedInterval( currentInterval );
+ // add i-th coordinate to domain, starting from (but excluding) innerDomain
+ extendedInterval[currentDim] = r_Sinterval( innerDomain.get_high()[currentDim]+1, outerDomain.get_high()[currentDim] );
+ // inspect next dimension
+ // RMInit::logOut << "QtExtend::extendGetCornerTiles(): recursing for upper end box in next dimension " << currentDim+1 << " using extendedInterval " << extendedInterval << endl;
+ extendGetCornerTiles( outerDomain, innerDomain, currentDim+1, maxDim, extendedInterval, cornerList );
+ }
+ }
+ else if (currentDim > maxDim)
+ {
+ // this is an error, see preconditions
+ RMInit::logOut << "QtExtend::extendGetCornerTiles(): error: dimension overflow." << endl;
+ }
+ else // then we've reached currentDim==maxDim
+ {
+ // add this minterval to the tile domain list
+ cornerList->push_back( currentInterval );
+ // RMInit::logOut << "QtExtend::extendGetCornerTiles(): added " << currentInterval << " to tile domain list." << endl;
+ }
+
+ // RMInit::logOut << "QtExtend::extendGetCornerTiles() done." << endl;
+}
+#endif 1
+
+void
+QtExtend::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtExtend Object " << getNodeType() << endl;
+
+ QtBinaryOperation::printTree( tab, s, mode );
+}
+
+
+
+void
+QtExtend::printAlgebraicExpression( ostream& s )
+{
+ s << "extend(";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ",";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+void
+QtExtend::optimizeLoad( QtTrimList* trimList )
+{
+ RMDBCLASS( "QtExtend", "optimizeLoad( QtTrimList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtNode::QtTrimList *list1=NULL, *list2=NULL;
+
+ if( input1 && input2 )
+ {
+#if 0 // not yet sure what to do -- PB 2005-06-18
+
+ QtNode::QtTrimList::iterator iter;
+
+ //
+ // The result of input2 has to be a constant expression.
+ //
+
+ // shift of trimList is just possible, if no open bounds are available
+ bool openBounds = false;
+ for( iter=trimList->begin(); iter!=trimList->end() && !openBounds; iter++ )
+ openBounds = !((*iter)->interval.is_low_fixed()) || !((*iter)->interval.is_high_fixed());
+
+ if( openBounds )
+ {
+ // release( trimList->begin(), trimList->end() );
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+
+ RMInit::logOut << "Error: QtExtend::optimizeLoad() - spatial domain shift of open bounds is not supported" << endl;
+// XXX need new error code
+ parseInfo.setErrorNo(409);
+ throw parseInfo;
+ }
+
+ QtData* operand = input2->evaluate(NULL);
+
+ if( !operand )
+ {
+ // release( trimList->begin(), trimList->end() );
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+
+ RMInit::logOut << "Error: QtExtend::optimizeLoad() - second operand of extend function must be a constant expression." << endl;
+// XXX correct new error code
+ parseInfo.setErrorNo(408);
+ throw parseInfo;
+ }
+
+ if( operand->getDataType() != QT_MINTERVAL )
+ {
+ // release( trimList->begin(), trimList->end() );
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+
+ operand->deleteRef();
+
+ RMInit::logOut << "Error: QtExtend::optimizeLoad() - second operand must be of type Minterval." << endl;
+// XXX correct new error code
+ parseInfo.setErrorNo(406);
+ throw parseInfo;
+ }
+
+ // get extend target domain
+ const r_Minterval& targetDomain = ((QtPointData*)operand)->getMintervalData();
+
+ // shift trim elements by -transPoint
+ // XXX replace with extend() code
+ for( iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ QtTrimElement* elem = *iter;
+
+ if( elem->dimension <= transPoint.dimension() )
+ elem->interval.set_interval( elem->interval.low() - transPoint[elem->dimension], elem->interval.high() - transPoint[elem->dimension] );
+ }
+
+ // point is not needed anymore
+ operand->deleteRef();
+#endif 0 // not yet sure what to do -- PB 2005-06-18
+
+ input1->optimizeLoad( trimList );
+ }
+ else
+ {
+ // release( trimList->begin(), trimList->end() );
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+ }
+}
+
+
+
+const QtTypeElement&
+QtExtend::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtExtend", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ // check operand branches
+ if( input1 && input2 )
+ {
+
+ // get input types
+ const QtTypeElement& inputType1 = input1->checkType( typeTuple );
+ const QtTypeElement& inputType2 = input2->checkType( typeTuple );
+
+ if( inputType1.getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Error: QtExtend::checkType() - first operand must be of type MDD." << endl;
+ parseInfo.setErrorNo(405);
+ throw parseInfo;
+ }
+
+ if( inputType2.getDataType() != QT_MINTERVAL )
+ {
+ RMInit::logOut << "Error: QtExtend::checkType() - second operand must be of type Minterval." << endl;
+ parseInfo.setErrorNo(422);
+ throw parseInfo;
+ }
+
+ // pass MDD type
+ dataStreamType = inputType1;
+ }
+ else
+ RMInit::logOut << "Error: QtExtend::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+
+
+// --- QtScale --------------------------------------------------
+
+const QtNode::QtNodeType QtScale::nodeType = QT_SCALE;
+
+QtScale::QtScale( QtOperation* mddOp, QtOperation* pointOp )
+ : QtBinaryOperation( mddOp, pointOp )
+{
+}
+
+
+
+bool
+QtScale::isCommutative() const
+{
+ return false; // NOT commutative
+}
+
+#include <iomanip>
+#include <math.h>
+
+// this define was used during testing, we had a problem
+inline double FLOOR(double a) {
+ return floor(a);
+}
+
+QtData*
+QtScale::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtScale", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+ QtData* operand1 = NULL;
+ QtData* operand2 = NULL;
+
+ if(!getOperands( inputList, operand1, operand2 ) )
+ return returnValue;
+
+ QtMDD* qtMDDObj = (QtMDD*)operand1;
+ MDDObj* currentMDDObj = qtMDDObj->getMDDObject();
+ vector<r_Double> scaleVector(0);
+
+ scaleVector = vector<r_Double>( qtMDDObj->getLoadDomain().dimension() );
+
+ r_Minterval sourceDomain = qtMDDObj->getLoadDomain();
+ r_Minterval targetDomain;
+ r_Point origin1 = sourceDomain.get_origin();
+ r_Point origin2 = qtMDDObj->getMDDObject()->getCurrentDomain().get_origin();
+
+ r_Minterval wishedTargetDomain;
+ r_Point translation;
+
+ //used for scale with wishedIv
+ bool isWishedTargetSet = false;
+ r_Double sourceRange=0., targetRange=0., f=0., Tl=0., Th=0.;
+
+ switch( operand2->getDataType() )
+ {
+ case QT_POINT:
+ {
+ const r_Point& transPoint = ((QtPointData*)operand2)->getPointData();
+
+ if( transPoint.dimension() != qtMDDObj->getLoadDomain().dimension() )
+ {
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ RMInit::logOut << "Error: QtScale::evaluate( QtDataList* ) - dimensionalities of MDD and scale expression are not matching." << endl;
+ parseInfo.setErrorNo(418);
+ throw parseInfo;
+ }
+
+ for( int i=0; i<scaleVector.size(); i++ )
+ scaleVector[i] = transPoint[i];
+ }
+ break;
+
+ case QT_CHAR:
+ case QT_USHORT:
+ case QT_ULONG:
+ {
+ for( int i=0; i<scaleVector.size(); i++ )
+ scaleVector[i] = ((QtAtomicData*)operand2)->getUnsignedValue();;
+ }
+ break;
+
+ case QT_OCTET:
+ case QT_SHORT:
+ case QT_LONG:
+ {
+ for( int i=0; i<scaleVector.size(); i++ )
+ scaleVector[i] = ((QtAtomicData*)operand2)->getSignedValue();;
+ }
+ break;
+
+ case QT_DOUBLE:
+ case QT_FLOAT:
+ {
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtScale", "Scaling: " << ((QtAtomicData*)operand2)->getDoubleValue() )
+ for( int i=0; i<scaleVector.size(); i++ )
+ scaleVector[i] = ((QtAtomicData*)operand2)->getDoubleValue();
+ }
+ break;
+
+ case QT_MINTERVAL:
+ {
+ wishedTargetDomain = ((QtMintervalData*)operand2)->getMintervalData();
+ isWishedTargetSet=true;
+
+ if( wishedTargetDomain.dimension() != sourceDomain.dimension())
+ {
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ RMInit::logOut << "Error: QtScale::evaluate( QtDataList* ) - dimensionalities of MDD and scale expression are not matching." << endl;
+ parseInfo.setErrorNo(418);
+ throw parseInfo;
+ }
+
+ for( int i=0; i<scaleVector.size(); i++ )
+ {
+ sourceRange = (r_Double)sourceDomain[i].get_extent();
+ targetRange = (r_Double)wishedTargetDomain[i].get_extent();
+
+ if(sourceRange != 0.)
+ {
+ scaleVector[i] = targetRange / sourceRange;
+ f = scaleVector[i];
+
+ Tl = FLOOR(f*sourceDomain[i].low());
+ //correction by 1e-6 to avoid the strage bug when Th was a
+ //integer value and floor return value-1(e.g. query 47.ql)
+ Th = FLOOR(f*(sourceDomain[i].high()+1) + 0.000001)-1;
+
+// FIXME BUG if(Tl != Th)
+// Th--;
+
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtScale", "Scale: before f="<<setprecision(12)<<f)
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtScale", "Scale: " << endl
+ <<"precalculated: "<<Tl<<':'<<Th<<"<-->"<<wishedTargetDomain[i].low()<<':'<<wishedTargetDomain[i].high()<<endl
+ <<"pro memoria: "<<(r_Range)(f*(sourceDomain[i].high()+1))<<", "<<(f*(sourceDomain[i].high()+1))
+ <<", "<<floor(f*(sourceDomain[i].high()+1))
+ <<", "<<ceil(f*(sourceDomain[i].high()+1)))
+
+ if( (Th-Tl+1) != targetRange )
+ {
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtScale", "Scale: correction necessary: "<<Tl<<':'<<Th<<"<-->"<<wishedTargetDomain[i].low()<<':'<<wishedTargetDomain[i].high())
+
+ f = f + (targetRange - (Th-Tl+1))/sourceRange;
+
+ // cout<<"f="<<setprecision(12)<<f<<" scale[i]="<<setprecision(12)<<scaleVector[i]<<endl;
+
+ Tl = FLOOR(f*sourceDomain[i].low());
+ //correction by 1e-6 to avoid the strage bug when Th was a
+ //integer value and floor return value-1(e.g. query 47.ql)
+ Th = FLOOR(f*(sourceDomain[i].high()+1) + 0.000001)-1;
+// FIXME BUG if(Tl != Th)
+// Th--;
+
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtScale", "Scale: ->: "<<Tl<<':'<<Th<<"<-->"<<wishedTargetDomain[i].low()<<':'<<wishedTargetDomain[i].high())
+
+ scaleVector[i]=f;
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtScale", "Scale: after f="<<setprecision(12)<<f)
+ }
+ }
+ else
+ {
+ scaleVector[i] =0; //exception? it can't heapen, this error is filtered long before reaching this point
+ }
+ }
+ }
+ break;
+ default:
+ RMDBGONCE(0, RMDebug::module_qlparser, "r_QtScale", "evaluate() bad type operand2" << operand2->getDataType());
+ break;
+ }
+
+// ----------------------------------------------------------
+
+#ifdef RMANDEBUG
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtScale", "Scale vector : " )
+ for( int i=0; i<scaleVector.size(); i++ )
+ {
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtScale", scaleVector[i] << "," )
+ }
+#endif
+
+ // scale domain
+ if( !scaleDomain( sourceDomain, scaleVector, targetDomain ) )
+ {
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ RMInit::logOut << "Error: QtScale::evaluate( QtDataList* ) - empty result after scaling." << endl;
+ parseInfo.setErrorNo(419);
+ throw parseInfo;
+ }
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtBinaryFunc", "Dummy target domain: " << targetDomain << endl )
+
+ if(isWishedTargetSet)
+ {
+ translation = wishedTargetDomain.get_origin() - targetDomain.get_origin();
+ targetDomain.translate(translation);
+ }
+
+ // create a transient MDD object for the query result
+ MDDObj* resultMDD = new MDDObj( currentMDDObj->getMDDBaseType(), targetDomain );
+
+ //**********************
+ origin1 = r_Point(scaleVector.size()); // all zero!!
+ //**********************
+
+ // get all tiles
+ vector<Tile* >* tiles = currentMDDObj->intersect( qtMDDObj->getLoadDomain() );
+
+ //tile domain before & after
+ r_Minterval sourceTileDomain, destinationTileDomain;
+
+ //
+ // Algorithm A: Scale each Tile
+ //
+
+ // iterate over source tiles
+ for( vector<Tile*>::iterator tileIter = tiles->begin(); tileIter != tiles->end(); tileIter++ )
+ {
+ // get relevant area of source tile
+ sourceTileDomain = qtMDDObj->getLoadDomain().create_intersection( (*tileIter)->getDomain() );
+
+ // compute scaled tile domain and check if it exists
+ if( (*tileIter)->scaleGetDomain( sourceTileDomain, scaleVector, destinationTileDomain) )
+ {
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtBinaryFunc", "Destination tile domain: " << destinationTileDomain << endl )
+ // create a new transient tile
+ Tile* newTransTile = new Tile( destinationTileDomain, currentMDDObj->getCellType() );
+ newTransTile->execScaleOp( *tileIter, sourceTileDomain, origin1, scaleVector );
+
+ if(isWishedTargetSet)
+ ((r_Minterval&)newTransTile->getDomain()).translate(translation);
+
+ resultMDD->insertTile( newTransTile );
+ }
+ }
+
+ // create a new QtMDD object as carrier object for the transient MDD object
+ returnValue = new QtMDD( (MDDObj*)resultMDD );
+
+ // delete the tile vector, the tiles itself are deleted when the destructor
+ // of the MDD object is called
+ delete tiles;
+ tiles=NULL;
+
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ return returnValue;
+}
+
+
+void
+QtScale::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtScale Object " << getNodeType() << endl;
+
+ QtBinaryOperation::printTree( tab, s, mode );
+}
+
+
+
+void
+QtScale::printAlgebraicExpression( ostream& s )
+{
+ s << "scale(";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ",";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+void
+QtScale::optimizeLoad( QtTrimList* trimList )
+{
+ RMDBCLASS( "QtScale", "optimizeLoad( QtTrimList* )", "qlparser", __FILE__, __LINE__ )
+
+ // by default, pass load domain to input1
+ if( input1 )
+ input1->optimizeLoad( trimList );
+ else
+ {
+ delete trimList;
+ trimList=NULL;
+ }
+}
+
+
+
+const QtTypeElement&
+QtScale::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtScale", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ // check operand branches
+ if( input1 && input2 )
+ {
+
+ // get input types
+ const QtTypeElement& inputType1 = input1->checkType( typeTuple );
+ const QtTypeElement& inputType2 = input2->checkType( typeTuple );
+
+ if( inputType1.getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Error: QtScale::checkType() - first operand must be of type MDD." << endl;
+ parseInfo.setErrorNo(416);
+ throw parseInfo;
+ }
+
+ if( inputType2.getDataType() != QT_POINT && inputType2.getDataType() != QT_MINTERVAL &&
+ inputType2.getDataType() != QT_FLOAT && inputType2.getDataType() != QT_DOUBLE &&
+ !inputType2.isInteger() )
+ {
+ RMInit::logOut << "Error: QtScale::checkType() - second operand must be either of type Point, Integer or Float." << endl;
+ parseInfo.setErrorNo(417);
+ throw parseInfo;
+ }
+
+ // pass MDD type
+ dataStreamType = inputType1;
+ }
+ else
+ RMInit::logOut << "Error: QtScale::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+
+int QtScale::scaleDomain( const r_Minterval& areaOp,
+ const vector<double>& scaleFactors,
+ r_Minterval &areaScaled )
+{
+ RMDBGENTER( 2, RMDebug::module_qlparser, "QtScale",
+ "scaleDomain( D: " << areaOp << ", F: " << scaleFactors << ", D: " << areaScaled << " )" )
+
+ try
+ {
+ areaScaled = areaOp.create_scale(scaleFactors);
+ }
+ catch(r_Error)
+ {
+ //error scaling
+ RMInit::logOut << "Error: QtScale::scaleDomain() - exception while determining scale target interval for " << areaOp << " and " << scaleFactors << endl;
+ return 0;
+ }
+
+ RMDBGEXIT( 2, RMDebug::module_qlparser, "QtScale", "scaleDomain(...) D: " << areaOp << " mapped to D: " << areaScaled )
+
+ return 1;
+}
+
+// origin1 von getLoadDomain
+// origin2 von getCurrentDomain
+
+int QtScale::scaleDomain( const r_Minterval& areaOp, const r_Point& origin1, const r_Point& origin2,
+ const vector<double>& scaleFactors, r_Minterval &areaScaled )
+{
+ RMDBGENTER( 2, RMDebug::module_qlparser,
+ "QtScale", "scaleDomain( D: " << areaOp << ", O1: " << origin1 << ", O2: " << origin2
+ << ", F: " << scaleFactors << " D: " << areaScaled << " )" )
+
+ r_Minterval tempIv=areaOp;
+
+ //reverse_translated with origin1
+ tempIv.reverse_translate(origin1);
+
+ //scale it normaly
+ if(!scaleDomain(tempIv, scaleFactors, areaScaled))
+ return 0;
+
+ //translate areaScaled to origin2
+ areaScaled.translate(origin2);
+
+ RMDBGEXIT( 2, RMDebug::module_qlparser, "QtScale", "scaledDomain(...) D: " << areaOp << " translated to D: " << areaScaled )
+
+ return 1;
+}
+