diff options
author | Constantin Jucovschi <cj@ubuntu.localdomain> | 2009-04-24 07:20:22 -0400 |
---|---|---|
committer | Constantin Jucovschi <cj@ubuntu.localdomain> | 2009-04-24 07:20:22 -0400 |
commit | 8f27e65bddd7d4b8515ce620fb485fdd78fcdf89 (patch) | |
tree | bd328a4dd4f92d32202241b5e3a7f36177792c5f /qlparser/qtdomainoperation.cc | |
download | rasdaman-upstream-8f27e65bddd7d4b8515ce620fb485fdd78fcdf89.tar.gz rasdaman-upstream-8f27e65bddd7d4b8515ce620fb485fdd78fcdf89.tar.xz rasdaman-upstream-8f27e65bddd7d4b8515ce620fb485fdd78fcdf89.zip |
Initial commitv8.0
Diffstat (limited to 'qlparser/qtdomainoperation.cc')
-rw-r--r-- | qlparser/qtdomainoperation.cc | 950 |
1 files changed, 950 insertions, 0 deletions
diff --git a/qlparser/qtdomainoperation.cc b/qlparser/qtdomainoperation.cc new file mode 100644 index 0000000..950c49d --- /dev/null +++ b/qlparser/qtdomainoperation.cc @@ -0,0 +1,950 @@ +/* +* 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: + * + ************************************************************/ + +static const char rcsid[] = "@(#)qlparser, QtTrim: $Id: qtdomainoperation.cc,v 1.35 2002/06/15 20:16:42 coman Exp $"; + +#include <vector> +#include <string> +using namespace std; + +#include "raslib/rmdebug.hh" + +#include "qlparser/qtmdd.hh" +#include "qlparser/qtunaryoperation.hh" +#include "qlparser/qtdomainoperation.hh" +#include "qlparser/qtnode.hh" +#include "qlparser/qtconst.hh" +#include "qlparser/qtmintervaldata.hh" +#include "qlparser/qtintervaldata.hh" +#include "qlparser/qtpointdata.hh" +#include "qlparser/qtatomicdata.hh" +#include "qlparser/qtcomplexdata.hh" + +#include "mddmgr/mddobj.hh" +#include "tilemgr/tile.hh" + +#include "catalogmgr/ops.hh" +#include "relcatalogif/mddbasetype.hh" +#include "relcatalogif/ulongtype.hh" + +#include <iostream> + + +const QtNode::QtNodeType QtDomainOperation::nodeType = QtNode::QT_DOMAIN_OPERATION; + + +QtDomainOperation::QtDomainOperation( QtOperation* mintOp ) + : mintervalOp( mintOp ), + dynamicMintervalExpression( true ) +{ + RMDBCLASS( "QtDomainOperation", "QtDomainOperation( QtOperation* )", "qlparser", __FILE__, __LINE__ ) + + if( mintervalOp ) mintervalOp->setParent( this ); +} + + + +QtDomainOperation::QtDomainOperation( r_Minterval domainNew, const vector<bool>* newTrimFlags ) + : mintervalOp(0), + dynamicMintervalExpression( false ) +{ + RMDBCLASS( "QtDomainOperation", "QtDomainOperation( r_Minterval, const vector<bool>* )", "qlparser", __FILE__, __LINE__ ) + + // make a copy + vector<bool>* trimFlags = new vector<bool>( *newTrimFlags ); + mintervalOp = new QtConst( new QtMintervalData( domainNew, trimFlags ) ); + mintervalOp->setParent( this ); +} + + + +QtDomainOperation::~QtDomainOperation() +{ + RMDBCLASS( "QtDomainOperation", "~QtDomainOperation()", "qlparser", __FILE__, __LINE__ ) + + if( mintervalOp ) + { + delete mintervalOp; + mintervalOp=NULL; + } +} + + + +QtNode::QtNodeList* +QtDomainOperation::getChilds( QtChildType flag ) +{ + RMDBCLASS( "QtDomainOperation", "getChilds( QtChildType )", "qlparser", __FILE__, __LINE__ ) + + QtNodeList* resultList=NULL; + + resultList = QtUnaryOperation::getChilds( flag ); + + if( mintervalOp ) + { + if( flag == QT_LEAF_NODES || flag == QT_ALL_NODES ) + { + QtNodeList* subList; + + subList = mintervalOp->getChilds( flag ); + + // remove all elements in subList and insert them at the beginning in resultList + resultList->splice( resultList->begin(), *subList ); + + // delete temporary subList + delete subList; + subList=NULL; + } + + // add the nodes of the current level + if( flag == QT_DIRECT_CHILDS || flag == QT_ALL_NODES ) + resultList->push_back( mintervalOp ); + } + + return resultList; +} + + + +bool +QtDomainOperation::equalMeaning( QtNode* node ) +{ + RMDBCLASS( "QtDomainOperation", "equalMeaning( QtNode* )", "qlparser", __FILE__, __LINE__ ) + + bool result = false; + + if( nodeType == node->getNodeType() ) + { + QtDomainOperation* domainNode; + domainNode = (QtDomainOperation*) node; // by force + + result = input->equalMeaning( domainNode->getInput() ) && + mintervalOp->equalMeaning( domainNode->getMintervalOp() ); + }; + + return ( result ); +} + + +string +QtDomainOperation::getSpelling() +{ + char tempStr[20]; + sprintf(tempStr, "%ud", (unsigned long)getNodeType()); + string result = string(tempStr); + result.append( mintervalOp->getSpelling() ); + result.append( "(" ); + result.append( input->getSpelling() ); + result.append( ")" ); + + return result; +} + + +void +QtDomainOperation::setInput( QtOperation* inputOld, QtOperation* inputNew ) +{ + QtUnaryOperation::setInput( inputOld, inputNew ); + + if( mintervalOp == inputOld ) + { + mintervalOp = inputNew; + + if( inputNew ) + inputNew->setParent( this ); + } +}; + + + +void +QtDomainOperation::optimizeLoad( QtTrimList* trimList ) +{ + RMDBCLASS( "QtDomainOperation", "optimizeLoad( QtTrimList* )", "qlparser", __FILE__, __LINE__ ) + + // test, if there is already a specification for that dimension + bool trimming = false; + + if( mintervalOp ) + { + // pass optimization to minterval tree + mintervalOp->optimizeLoad( new QtNode::QtTrimList ); + + // evaluate minterval tree + QtData* operand = mintervalOp->evaluate(NULL); + + // if spatial operation could be determined, it is static + dynamicMintervalExpression = !operand; + + if( operand ) + { + if( operand->getDataType() == QT_MINTERVAL ) + { + r_Minterval domain = ((QtMintervalData*)operand)->getMintervalData(); + vector<bool>* trimFlags = new vector<bool>( *(((QtMintervalData*)operand)->getTrimFlags()) ); + + if( trimList && trimList->empty() ) + { + // no previous specification for that dimension + trimming = true; + for( int i=0; i!=domain.dimension(); i++ ) + { + // create a new element + QtTrimElement* elem = new QtTrimElement; + + elem->interval = domain[i]; + elem->intervalFlag = (*trimFlags)[i]; + elem->dimension = i; + + // and add it to the list + trimList->push_back( elem ); + + trimming &= (*trimFlags)[i]; + } + } + else + { + // previous specification exists, test for compatibility + } + + if( trimFlags ) + { + delete trimFlags; + trimFlags = NULL; + } + } + + // else if( operand->getDataType() == QtData::QT_POINT ) + + // delete the operand + operand->deleteRef(); + } + } + + // pass optimization process to the input tree + if( input ) input->optimizeLoad( trimList ); + + // Eliminate node QtDomainOperation if only trimming occurs. + if( trimming ) + { + RMDBGMIDDLE(2, RMDebug::module_qlparser, "QtDomainOperation", "all trimming") + + getParent()->setInput( this, input ); + + // Delete the node itself after resetting its input because + // otherwise the input is delete either. + setInput( input, NULL ); + delete this; + } +} + + + +QtData* +QtDomainOperation::evaluate( QtDataList* inputList ) +{ + RMDBCLASS( "QtDomainOperation", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ ) + + QtData* returnValue = NULL; + + switch( input->getDataStreamType().getDataType() ) + { + case QT_MDD: + { + if( mintervalOp->getDataStreamType().getDataType() == QT_POINT || + mintervalOp->getDataStreamType().isInteger() ) + { + // + // Projection to one cell. + // + + QtData* indexData = mintervalOp->evaluate( inputList ); + + if( !indexData ) + return 0; + +#ifdef QT_RUNTIME_TYPE_CHECK + if( indexData->getDataType() != QT_POINT && + !indexData->getDataType().isInteger() ) + { + RMInit::logOut << "Internal error in QtDomainOperation::evaluate() - " + << "runtime type checking failed (QT_POINT, INTEGER)." << endl; + + // delete index data + indexData->deleteRef(); + + return 0; + } +#endif + + // get projection point + r_Point projPoint; + + if( indexData->getDataType() == QT_POINT ) + { + projPoint = ((QtPointData*)indexData)->getPointData(); + } + else + { + projPoint = r_Point(1); + + if( indexData->getDataType() == QT_SHORT || + indexData->getDataType() == QT_OCTET || + indexData->getDataType() == QT_LONG ) + projPoint[0] = ((QtAtomicData*)indexData)->getSignedValue(); + else + projPoint[0] = ((QtAtomicData*)indexData)->getUnsignedValue(); + + } + + // + // In case of dynamic index expressions, load optimization has to + // be performed for the current input expression. + // + /* + if( dynamicMintervalExpression ) + { + QtNode::QtTrimList* trimList = new QtNode::QtTrimList; + + for( int i=0; i!=domain.dimension(); i++ ) + { + // create a new element + QtTrimElement* elem = new QtTrimElement; + + elem->interval = domain[i]; + elem->intervalFlag = (*trimFlags)[i]; + elem->dimension = i; + + // and add it to the list + trimList->push_back( elem ); + } + + // pass optimization process to the input tree + input->optimizeLoad( trimList ); + } + */ + + // get operand data + QtData* operand = input->evaluate( inputList ); + + if( !operand ) + { + // delete indexData + indexData->deleteRef(); + + return 0; + } + +#ifdef QT_RUNTIME_TYPE_CHECK + if( operand->getDataType() != QT_MDD ) + { + RMInit::logOut << "Internal error in QtDomainOperation::evaluate() - runtime type checking failed (QT_MDD)." << endl; + + // delete index and operand data + indexData->deleteRef(); + operand ->deleteRef(); + + return 0; + } +#endif + + QtMDD* qtMDD = (QtMDD*) operand; + MDDObj* currentMDDObj = qtMDD->getMDDObject(); + + if( currentMDDObj ) + { + RMDBGMIDDLE(2, RMDebug::module_qlparser, "QtDomainOperation", " mdd domain: " << currentMDDObj->getCurrentDomain() ) + RMDBGMIDDLE(2, RMDebug::module_qlparser, "QtDomainOperation", " mdd load domain: " << qtMDD->getLoadDomain() ) + + // reset loadDomain to intersection of domain and loadDomain + // if( domain.intersection_with( qtMDD->getLoadDomain() ) != qtMDD->getLoadDomain() ) + // qtMDD->setLoadDomain( domain.intersection_with( qtMDD->getLoadDomain() ) ); + + // get type of cell + const BaseType* cellType = ((MDDBaseType*)(currentMDDObj->getMDDBaseType()))->getBaseType(); + + RMDBGMIDDLE(2, RMDebug::module_qlparser, "QtDomainOperation", " point access: " << projPoint ) + const char* resultCell = NULL; + if (projPoint.dimension() == currentMDDObj->getDimension()) + resultCell = currentMDDObj->pointQuery( projPoint ); + if (resultCell == NULL) + { + RMInit::logOut << "Error: QtDomainOperation::evaluate() - projected cell is not defined." << endl; + parseInfo.setErrorNo(356); + + // delete index and operand data + indexData->deleteRef(); + operand ->deleteRef(); + + throw parseInfo; + } + + // allocate cell buffer + char* resultBuffer = new char[ cellType->getSize() ]; + + // copy cell content + memcpy( (void*)resultBuffer, (void*)resultCell, cellType->getSize() ); + + // create data object for the cell + QtScalarData* scalarDataObj = NULL; + if( cellType->getType() == STRUCT ) + scalarDataObj = new QtComplexData(); + else + scalarDataObj = new QtAtomicData(); + + scalarDataObj->setValueType ( cellType ); + scalarDataObj->setValueBuffer( resultBuffer ); + + // set return data object + returnValue = scalarDataObj; + } + + // delete indexData + indexData->deleteRef(); + + // delete old operand + operand->deleteRef(); + + } + else // mintervalOp->getDataStreamType() == QT_MINTERVAL + { + // + // Trimming/Projection to an MDD object + // + QtData* indexData = mintervalOp->evaluate( inputList ); + + if( !indexData ) + return 0; + +#ifdef QT_RUNTIME_TYPE_CHECK + if( indexData->getDataType() != QT_MINTERVAL ) + { + RMInit::logOut << "Internal error in QtDomainOperation::evaluate() - " + << "runtime type checking failed (QT_MINTERVAL)." << endl; + + // delete index data + indexData->deleteRef(); + + return 0; + } +#endif + + // get minterval data + vector<bool>* trimFlags = new vector<bool>( *(((QtMintervalData*)indexData)->getTrimFlags()) ); + r_Minterval domain = ((QtMintervalData*)indexData)->getMintervalData(); + + // + // In case of dynamic index expressions, load optimization has to + // be performed for the current input expression. + // + + if( dynamicMintervalExpression ) + { + QtNode::QtTrimList* trimList = new QtNode::QtTrimList; + + for( int i=0; i!=domain.dimension(); i++ ) + { + // create a new element + QtTrimElement* elem = new QtTrimElement; + + elem->interval = domain[i]; + elem->intervalFlag = (*trimFlags)[i]; + elem->dimension = i; + + // and add it to the list + trimList->push_back( elem ); + } + + // pass optimization process to the input tree + input->optimizeLoad( trimList ); + } + + // get operand data + QtData* operand = input->evaluate( inputList ); + + if( !operand ) + { + // delete index data + indexData->deleteRef(); + return 0; + } + +#ifdef QT_RUNTIME_TYPE_CHECK + if( operand->getDataType() != QT_MDD ) + { + RMInit::logOut << "Internal error in QtDomainOperation::evaluate() - runtime type checking failed (QT_MDD)." << endl; + + // delete index and operand data + indexData->deleteRef(); + operand ->deleteRef(); + + return 0; + } +#endif + + QtMDD* qtMDD = (QtMDD*) operand; + MDDObj* currentMDDObj = qtMDD->getMDDObject(); + + if( currentMDDObj ) + { + bool trimming = false; + bool projection = false; + + // reset loadDomain to intersection of domain and loadDomain + if( domain.intersection_with( qtMDD->getLoadDomain() ) != qtMDD->getLoadDomain() ) + qtMDD->setLoadDomain( domain.intersection_with( qtMDD->getLoadDomain() ) ); + + // Test, if trimming has to be done; trimming = 1 if !(load domain is subset of spatial operation) + trimming = ( domain.intersection_with( qtMDD->getLoadDomain() ) == qtMDD->getLoadDomain() ); + + // Test, if a projection has to be made and build the projSet in projection case + set< r_Dimension, less<r_Dimension> > projSet; + + for( int i=0; i<trimFlags->size(); i++ ) + if( !(*trimFlags)[i] ) + { + projection = true; + projSet.insert( i ); + } + + r_Minterval projectedDom( domain.dimension() - projSet.size() ); + + // build the projected domain + for( int i = 0; i < domain.dimension(); i++ ) + // do not include dimensions projected away + if(projSet.find(i) == projSet.end()) + projectedDom << domain[i]; + + if( trimFlags ) + { + delete trimFlags; + trimFlags = NULL; + } + + RMDBGMIDDLE(2, RMDebug::module_qlparser, "QtDomainOperation", " operation domain..: " << domain << " with projection " << projectedDom ) + RMDBGMIDDLE(2, RMDebug::module_qlparser, "QtDomainOperation", " mdd load domain: " << qtMDD->getLoadDomain() ) + RMDBGMIDDLE(2, RMDebug::module_qlparser, "QtDomainOperation", " mdd current domain: " << currentMDDObj->getCurrentDomain() ) + + if( trimming || projection ) + { + // get relevant tiles + vector<Tile* >* relevantTiles = currentMDDObj->intersect( domain ); + + if( relevantTiles->size() > 0 ) + { + // iterator for tiles + vector<Tile*>::iterator tileIt; + + // create a transient MDD object for the query result + MDDObj* resultMDD = new MDDObj( currentMDDObj->getMDDBaseType(), projectedDom ); + + // and iterate over them + for( tileIt = relevantTiles->begin(); tileIt != relevantTiles->end(); tileIt++ ) + { + // domain of the actual tile + r_Minterval tileDom = (*tileIt)->getDomain(); + + // domain of the relevant area of the actual tile + r_Minterval intersectDom = tileDom.create_intersection( domain ); + + RMDBGMIDDLE(2, RMDebug::module_qlparser, "QtDomainOperation", " trimming/projecting tile with domain " << tileDom << " to domain " << intersectDom ) + + // create projected tile + Tile* resTile = new Tile( (*tileIt), intersectDom, &projSet ); + + // insert Tile in result mddObj + resultMDD->insertTile( resTile ); + } + + // create a new QtMDD object as carrier object for the transient MDD object + returnValue = new QtMDD( (MDDObj*)resultMDD ); + + // delete the tile vector + delete relevantTiles; + relevantTiles=NULL; + } + else + { + RMInit::logOut << "Error: QtDomainOperation::evaluate() - the load domain does not intersect with tiles in the current MDD." << endl; + parseInfo.setErrorNo(356); + + // delete index and operand data + indexData->deleteRef(); + operand ->deleteRef(); + + throw parseInfo; + } + + } // trimming || projection + else + // operand is passed through + returnValue = operand; + + } // if( currentMDDObj ) + + // delete index and operand data + if( indexData ) indexData->deleteRef(); + if( operand ) operand ->deleteRef(); + + } + break; + } + case QT_MINTERVAL: + { + QtData* operandData = NULL; + QtData* indexData = NULL; + + operandData = input->evaluate( inputList ); + + if( operandData ) + { +#ifdef QT_RUNTIME_TYPE_CHECK + if( operandData->getDataType() != QT_MINTERVAL ) + { + RMInit::logOut << "Internal error in QtDomainOperation::evaluate() - runtime type checking failed (QT_MINTERVAL)." << endl; + return 0; + } +#endif + // get point + const r_Minterval& minterval = ((QtMintervalData*)operandData)->getMintervalData(); + + // get index + indexData = mintervalOp->evaluate( inputList ); + +#ifdef QT_RUNTIME_TYPE_CHECK + if( indexData->getDataType() != QT_POINT && indexData->getDataType() != QT_CHAR && + indexData->getDataType() != QT_USHORT && indexData->getDataType() != QT_ULONG ) + { + RMInit::logOut << "Internal error in QtDomainOperation::evaluate() - runtime type checking failed." << endl; + return 0; + } +#endif + r_Dimension indexValue = 0; + + switch( indexData->getDataType() ) + { + case QT_POINT: + { + // get first element as index + const r_Point& indexPoint = ((QtPointData*)indexData)->getPointData(); + + if( indexPoint.dimension() != 1 ) + { + RMInit::logOut << "Error: QtDomainOperation::evaluate() - Operand of minterval selection must be of type unsigned integer." << endl; + parseInfo.setErrorNo(397); + + // delete ressources + if( operandData ) operandData->deleteRef(); + if( indexData ) indexData ->deleteRef(); + + throw parseInfo; + } + + indexValue = indexPoint[0]; + } + break; + + case QT_CHAR: + case QT_USHORT: + case QT_ULONG: + indexValue = ((QtAtomicData*)indexData)->getUnsignedValue(); + break; + + case QT_OCTET: + case QT_SHORT: + case QT_LONG: + indexValue = ((QtAtomicData*)indexData)->getSignedValue(); + break; + default: + RMDBGONCE(0, RMDebug::module_qlparser, "r_QtDomainOperation", "evaluate() bad type " << indexData->getDataType()); + break; + } +//indexValue is a unsigned type -> there will never be a indexVAlue < 0 + if( /*indexValue < 0 ||*/ indexValue >= minterval.dimension() ) + { + RMInit::logOut << "Error: QtDomainOperation::evaluate() - index for minterval selection is out of range." << endl; + parseInfo.setErrorNo(398); + + // delete ressources + if( operandData ) operandData->deleteRef(); + if( indexData ) indexData ->deleteRef(); + + throw parseInfo; + } + + returnValue = new QtIntervalData( minterval[indexValue] ); + } + + // delete ressources + if( operandData ) operandData->deleteRef(); + if( indexData ) indexData ->deleteRef(); + break; + } + + case QT_POINT: + { + QtData* operandData = NULL; + QtData* indexData = NULL; + + operandData = input->evaluate( inputList ); + + if( operandData ) + { +#ifdef QT_RUNTIME_TYPE_CHECK + if( operandData->getDataType() != QT_POINT ) + { + RMInit::logOut << "Internal error in QtDomainOperation::evaluate() - runtime type checking failed (QT_POINT)." << endl; + return 0; + } +#endif + // get point + const r_Point& pt = ((QtPointData*)operandData)->getPointData(); + + // get index + indexData = mintervalOp->evaluate( inputList ); + +#ifdef QT_RUNTIME_TYPE_CHECK + if( indexData->getDataType() != QT_POINT && indexData->getDataType() != QT_CHAR && + indexData->getDataType() != QT_USHORT && indexData->getDataType() != QT_ULONG ) + { + RMInit::logOut << "Internal error in QtDomainOperation::evaluate() - runtime type checking failed." << endl; + return 0; + } +#endif + r_Dimension indexValue = 0; + + switch( indexData->getDataType() ) + { + case QT_POINT: + { + // get first element as index + const r_Point& indexPoint = ((QtPointData*)indexData)->getPointData(); + + if( indexPoint.dimension() != 1 ) + { + RMInit::logOut << "Error: QtDomainOperation::evaluate() - Operand of point selection must be of type unsigned integer." << endl; + parseInfo.setErrorNo(399); + + // delete ressources + if( operandData ) operandData->deleteRef(); + if( indexData ) indexData ->deleteRef(); + + throw parseInfo; + } + + indexValue = indexPoint[0]; + } + break; + + case QT_CHAR: + case QT_USHORT: + case QT_ULONG: + indexValue = ((QtAtomicData*)indexData)->getUnsignedValue(); + break; + + case QT_OCTET: + case QT_SHORT: + case QT_LONG: + indexValue = ((QtAtomicData*)indexData)->getSignedValue(); + break; + default: + RMDBGONCE(0, RMDebug::module_qlparser, "r_QtDomainOperation", "evaluate() 2 - bad type " << indexData->getDataType()); + break; + } + + //indexValue is a unsigned type -> there will never be a indexValue < 0 + if( /*indexValue < 0 ||*/ indexValue >= pt.dimension() ) + { + RMInit::logOut << "Error: QtDomainOperation::evaluate() - index for point selection is out of range." << endl; + parseInfo.setErrorNo(411); + + // delete ressources + if( operandData ) operandData->deleteRef(); + if( indexData ) indexData ->deleteRef(); + + throw parseInfo; + } + + returnValue = new QtAtomicData( (r_Long)pt[indexValue], 4 ); + } + + // delete ressources + if( operandData ) operandData->deleteRef(); + if( indexData ) indexData ->deleteRef(); + break; + } + + default: + { + RMInit::logOut << "Error: QtDomainOperation::evaluate() - selection operation is not supported on this data type." << endl; + parseInfo.setErrorNo(396); + throw parseInfo; + } + } + + return returnValue; +} + + +void +QtDomainOperation::printTree( int tab, ostream& s, QtChildType mode ) +{ + s << SPACE_STR(tab).c_str() << "QtDomainOperation Object: type " << flush; + dataStreamType.printStatus( s ); + s << endl; + + if( mintervalOp ) + { + s << SPACE_STR(tab).c_str() << "spatial operation: " << endl; + mintervalOp->printTree( tab + 2, s ); + } + else + s << SPACE_STR(tab).c_str() << "no spatial operation" << endl; + + QtUnaryOperation::printTree( tab, s, mode ); +} + + + +void +QtDomainOperation::printAlgebraicExpression( ostream& s ) +{ + s << "geo("; + + if( mintervalOp ) + mintervalOp->printAlgebraicExpression( s ); + else + s << "<nn>"; + + s << ","; + + if( input ) + input->printAlgebraicExpression( s ); + else + s << "<nn>"; + + s << ")"; +} + + + +const QtTypeElement& +QtDomainOperation::checkType( QtTypeTuple* typeTuple ) +{ + RMDBCLASS( "QtDomainOperation", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ ) + + dataStreamType.setDataType( QT_TYPE_UNKNOWN ); + + // + // operation signatures + // + // MDD<T,D> x Minterval -> MDD<T,D> + // // MDD<T,D> x Interval -> MDD<T,D> + // MDD<T,D> x Point -> T + // MDD<T,D> x Integer -> T + // Minterval x Integer -> Interval + // Minterval x Point(1) -> Interval + // Point x Integer -> Integer + // Point x Point(1) -> Integer + // + + // check operand branches + if( input && mintervalOp ) + { + + // 1. check input expression type + const QtTypeElement& inputType = input->checkType( typeTuple ); + + // 2. check index expression type + const QtTypeElement& indexType = mintervalOp->checkType( typeTuple ); + + // 3. determine result type + if( inputType.getDataType() == QT_MDD ) + { + // check index type + if( indexType.getDataType() != QT_MINTERVAL + // && indexType.getDataType() != QT_INTERVAL + && indexType.getDataType() != QT_POINT + && !indexType.isInteger() + ) + { + RMInit::logOut << "Error: QtDomainOperation::checkType() - spatial domain expressions must be either of type minterval, point, or integer." << endl; + parseInfo.setErrorNo(391); + throw parseInfo; + } + + // MDD + if( indexType.getDataType() == QT_MINTERVAL /* || indexType.getDataType() == QT_INTERVAL */ ) + // pass MDD type + dataStreamType = inputType; + else + // use MDD cell type + dataStreamType.setType( ((MDDBaseType*)inputType.getType())->getBaseType() ); + } + else if( inputType.getDataType() == QT_MINTERVAL ) + { + // check index type + if( !indexType.isInteger() && indexType.getDataType() != QT_POINT ) + { + RMInit::logOut << "Error: QtDomainOperation::checkType() - Operand of minterval selection must be of type integer." << endl; + parseInfo.setErrorNo(397); + throw parseInfo; + } + + dataStreamType.setDataType( QT_INTERVAL ); + } + else if( inputType.getDataType() == QT_POINT ) + { + // check index type + if( !indexType.isInteger() && indexType.getDataType() != QT_POINT ) + { + RMInit::logOut << "Error: QtDomainOperation::checkType() - Operand of point selection must be of type integer." << endl; + parseInfo.setErrorNo(399); + throw parseInfo; + } + + dataStreamType.setDataType( QT_ULONG ); + } + else + { + RMInit::logOut << "Error: QtDomainOperation::checkType() - selection operation is not supported on this data type." << endl; + parseInfo.setErrorNo(396); + throw parseInfo; + } + } + else + RMInit::logOut << "Error: QtDomainOperation::checkType() - input or index branch invalid." << endl; + + return dataStreamType; +} + + |