/* * 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: * ************************************************************/ static const char rcsid[] = "@(#)qlparser, QtBinaryInduce: $Id: qtbinaryinduce.cc,v 1.47 2003/12/27 20:39:35 rasdev Exp $"; #include "raslib/rmdebug.hh" #include "debug.hh" #include "qlparser/qtbinaryinduce.hh" #include "qlparser/qtatomicdata.hh" #include "qlparser/qtcomplexdata.hh" #include "qlparser/qtconst.hh" #include "qlparser/qtstringdata.hh" #include "mddmgr/mddobj.hh" #include "catalogmgr/typefactory.hh" #include "relcatalogif/mdddomaintype.hh" #include "tilemgr/tile.hh" #include #include #include #include using namespace std; const QtNode::QtNodeType QtBinaryInduce::nodeType = QtNode::QT_BINARY_INDUCE; QtBinaryInduce::QtBinaryInduce( QtOperation* initInput1, QtOperation* initInput2, Ops::OpType initOpType ) : QtBinaryOperation( initInput1, initInput2 ), opType( initOpType ) { } QtData* QtBinaryInduce::computeOp( QtData* operand1, QtData* operand2 ) { RMDBCLASS( "QtBinaryInduce", "computeOp( QtData*, QtData* )", "qlparser", __FILE__, __LINE__ ) QtData* returnValue = NULL; if ( operand1->getDataType() == QT_MDD && operand2->getDataType() == QT_MDD ) { QtMDD* mdd1 = (QtMDD*) operand1; QtMDD* mdd2 = (QtMDD*) operand2; const BaseType* resultBaseType = ((MDDBaseType*)(dataStreamType.getType()))->getBaseType(); returnValue = computeBinaryMDDOp( mdd1, mdd2, resultBaseType ); } else if( operand1->getDataType() == QT_MDD && operand2->isScalarData() ) { QtMDD* mdd = (QtMDD*) operand1; QtScalarData* scalar = (QtScalarData*) operand2; const BaseType* resultBaseType = ((MDDBaseType*)(dataStreamType.getType()))->getBaseType(); returnValue = computeUnaryMDDOp( mdd, scalar, resultBaseType, 2 ); } else if( operand1->isScalarData() && operand2->getDataType() == QT_MDD ) { QtMDD* mdd = (QtMDD*) operand2; QtScalarData* scalar = (QtScalarData*) operand1; const BaseType* resultBaseType = ((MDDBaseType*)(dataStreamType.getType()))->getBaseType(); returnValue = computeUnaryMDDOp( mdd, scalar, resultBaseType, 1 ); } else if( operand1->isScalarData() && operand2->isScalarData() ) { QtScalarData* scalar1 = (QtScalarData*) operand1; QtScalarData* scalar2 = (QtScalarData*) operand2; BaseType* resultBaseType = (BaseType*)(dataStreamType.getType()); returnValue = computeBinaryOp( scalar1, scalar2, resultBaseType ); } else if( operand1->getDataType() == QT_STRING && operand2->getDataType() == QT_STRING ) { // opType == Ops::OP_EQUAL QtStringData* strObj1 = (QtStringData*) operand1; QtStringData* strObj2 = (QtStringData*) operand2; bool booleanResult = strObj1->getStringData() == strObj2->getStringData(); returnValue = new QtAtomicData( booleanResult ); } return returnValue; } QtData* QtBinaryInduce::computeUnaryMDDOp( QtMDD* operand1, QtScalarData* operand2, const BaseType* resultBaseType, int scalarPos ) { RMDBCLASS( "QtBinaryInduce", "computeUnaryMDDOp( QtMDD*, QtScalarData*, BaseType*, int )", "qlparser", __FILE__, __LINE__ ) QtData* returnValue = NULL; // get the MDD object MDDObj* op = operand1->getMDDObject(); // create ULong type with QtIntData value const BaseType* constBaseType = operand2->getValueType(); const char* constValue = operand2->getValueBuffer(); // get the area, where the operation has to be applied const r_Minterval &areaOp = operand1->getLoadDomain(); // contains all tiles of the operand vector* allTiles=NULL; // iterator for tiles vector::iterator tileIt; // create MDDObj for result MDDDomainType* mddBaseType = new MDDDomainType( "tmp", resultBaseType, areaOp ); TypeFactory::addTempType( mddBaseType ); MDDObj* mddres = new MDDObj( mddBaseType, areaOp ); // get all tiles in relevant area allTiles = op->intersect(areaOp); tileIt = allTiles->begin(); //auto_ptr myOp(NULL); BinaryOp* myOp = NULL; if (tileIt != allTiles->end()) { if (scalarPos == 1) //myOp.reset(Ops::getBinaryOp(opType, resultBaseType, constBaseType, (*tileIt)->getType())); myOp = (Ops::getBinaryOp(opType, resultBaseType, constBaseType, (*tileIt)->getType())); else //myOp.reset(Ops::getBinaryOp(opType, resultBaseType, (*tileIt)->getType(), constBaseType)); myOp = (Ops::getBinaryOp(opType, resultBaseType, (*tileIt)->getType(), constBaseType)); } // and iterate over them for( ; tileIt != allTiles->end(); tileIt++ ) { // domain of the actual tile const r_Minterval &tileDom = (*tileIt)->getDomain(); // domain of the relevant area of the actual tile r_Minterval intersectDom( tileDom.create_intersection( areaOp ) ); // create tile for result Tile* resTile = new Tile( intersectDom, resultBaseType ); // // carry out operation on the relevant area of the tiles // RMDBGIF( 4, RMDebug::module_qlparser, "QtScale", \ char* typeStructure = resTile->getType()->getTypeStructure(); \ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " result tile, area " << intersectDom << \ ", type " << resTile->getType()->getTypeName() << \ ", structure " << typeStructure << endl ) \ free( typeStructure ); typeStructure=NULL; \ \ typeStructure = (*tileIt)->getType()->getTypeStructure(); \ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " operand1 tile, area " << intersectDom << \ ", type " << (*tileIt)->getType()->getTypeName() << \ ", structure " << typeStructure << endl ) \ free( typeStructure ); typeStructure=NULL; \ typeStructure = constBaseType->getTypeStructure(); \ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " constant type " << constBaseType->getTypeName() << \ ", structure " << typeStructure << \ ", value " ) \ free( typeStructure ); typeStructure=NULL; \ \ for( int x=0; xgetSize(); x++ ) \ RMInit::dbgOut << hex << (int)(constValue[x]); \ RMInit::dbgOut << dec << endl; \ ) RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " before execConstOp" << endl ) resTile->execConstOp( myOp, intersectDom, (*tileIt), intersectDom, constValue, scalarPos ); //resTile->execConstOp( opType, intersectDom, (*tileIt), intersectDom, constValue, constBaseType, scalarPos ); RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " after execConstOp" << endl ) // insert Tile in result tile mddres->insertTile( resTile ); } delete myOp; myOp = NULL; // delete tile vector delete allTiles; allTiles=NULL; // create a new QtMDD object as carrier object for the transient MDD object returnValue = new QtMDD( (MDDObj*)mddres ); // The following is now done, when the last reference is deleted. // delete the obsolete MDD object // delete op; return returnValue; } QtData* QtBinaryInduce::computeBinaryMDDOp( QtMDD* operand1, QtMDD* operand2, const BaseType* resultBaseType ) { RMDBCLASS( "QtBinaryInduce", "computeBinaryMDDOp( QtMDD*, QtMDD*, BaseType* )", "qlparser", __FILE__, __LINE__ ) QtData* returnValue = NULL; // get the MDD objects MDDObj* op1 = operand1->getMDDObject(); MDDObj* op2 = operand2->getMDDObject(); // get the areas, where the operation has to be applied const r_Minterval &areaOp1 = operand1->getLoadDomain(); const r_Minterval &areaOp2 = operand2->getLoadDomain(); // Check, if the domains are compatible which means that they have the same // dimensionality and each dimension has the same number of elements. if( areaOp1.get_extent() == areaOp2.get_extent() ) { // contains all tiles of op1 vector* allTilesOp1=NULL; // contains all tiles of op2 which intersect a given op1 Tile in the relevant area. vector* intersectTilesOp2=NULL; // iterators for tiles of the MDDs vector::iterator tileOp1It; vector::iterator intersectTileOp2It; // intersection of domains in relevant area. r_Minterval intersectDom; // pointer to generated result tile Tile* resTile=NULL; // MDDObj for result MDDObj* mddres=NULL; // translations between the two areas r_Point offset12(areaOp1.dimension()); r_Point offset21(areaOp1.dimension()); // calculate translations r_Point originOp1 = areaOp1.get_origin(); r_Point originOp2 = areaOp2.get_origin(); for(r_Dimension i = 0; iintersect(areaOp1); // cout << "INTERSECT" << areaOp1 << endl; // for( tileOp1It = allTilesOp1->begin(); tileOp1It != allTilesOp1->end(); tileOp1It++ ) // cout << (*tileOp1It)->getDomain() << endl; // and iterate over them auto_ptr myOp(Ops::getBinaryOp(opType, mddBaseType->getBaseType(), op1->getCellType(), op2->getCellType())); for( tileOp1It = allTilesOp1->begin(); tileOp1It != allTilesOp1->end(); tileOp1It++ ) { // domain of the op1 tile const r_Minterval &tileOp1Dom = (*tileOp1It)->getDomain(); // relevant area of op1's domain r_Minterval intersectionTileOp1Dom( tileOp1Dom.create_intersection( areaOp1 ) ); // intersect relevant area of the tile with MDD op2 (including translation) intersectTilesOp2 = op2->intersect(intersectionTileOp1Dom.create_translation(offset12)); // cout << "INTERSECT" << tileOp1Dom.create_translation(offset12) << endl; // for( intersectTileOp2It = intersectTilesOp2->begin(); // intersectTileOp2It != intersectTilesOp2->end(); // intersectTileOp2It++ ) // cout << (*intersectTileOp2It)->getDomain() << endl; // iterate over intersecting tiles for( intersectTileOp2It = intersectTilesOp2->begin(); intersectTileOp2It != intersectTilesOp2->end(); intersectTileOp2It++ ) { const r_Minterval &tileOp2Dom = (*intersectTileOp2It)->getDomain(); // the relevant domain is the intersection of the // domains of the two tiles with the relevant area. intersectDom = tileOp1Dom.create_intersection(tileOp2Dom.create_translation(offset21)); intersectDom.intersection_with(areaOp1); // create tile for result resTile = new Tile( intersectDom, resultBaseType ); // // carry out operation on the relevant area of the tiles // RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " before execBinaryOp" << endl ) RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " result tile, area " << intersectDom << ", type " << resTile->getType()->getTypeName() << endl ) RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " operand1 tile, area " << intersectDom << ", type " << (*tileOp1It)->getType()->getTypeName() << endl ) RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " operand2 tile, type " << (*tileOp1It)->getType()->getTypeName() << endl ) resTile->execBinaryOp(&(*myOp), intersectDom, (*tileOp1It), intersectDom, (*intersectTileOp2It), intersectDom.create_translation(offset12)); RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " after execBinaryOp" << endl ) // insert Tile in result mddobj mddres->insertTile( resTile ); } delete intersectTilesOp2; intersectTilesOp2=NULL; } delete allTilesOp1; allTilesOp1=NULL; // create a new QtMDD object as carrier object for the transient MDD object returnValue = new QtMDD( (MDDObj*)mddres ); } else { RMInit::logOut << "Error: QtBinaryInduce::computeBinaryMDDOp() - domains of the operands are incompatible." << endl; RMInit::logOut << "areaOp1 " << areaOp1 << " with extent " << areaOp1.get_extent() << endl; RMInit::logOut << "areaOp2 " << areaOp2 << " with extent " << areaOp2.get_extent() << endl; parseInfo.setErrorNo(351); throw parseInfo; } // The following is now done, when the last reference is deleted. // delete obsolete MDD objects // delete op1; // delete op2; return returnValue; } QtData* QtBinaryInduce::computeBinaryOp( QtScalarData* operand1, QtScalarData* operand2, const BaseType* resultBaseType ) { RMDBCLASS( "QtBinaryInduce", "computeBinaryOp( QtScalarData*, QtScalarData*, BaseType*, Ops::OpType )", "qlparser", __FILE__, __LINE__ ) QtScalarData* scalarDataObj = NULL; // allocate memory for the result char* resultBuffer = new char[ resultBaseType->getSize() ]; Ops::execBinaryConstOp( opType, resultBaseType, operand1->getValueType(), operand2->getValueType(), resultBuffer, operand1->getValueBuffer(), operand2->getValueBuffer() ); if( resultBaseType->getType() == STRUCT ) scalarDataObj = new QtComplexData(); else scalarDataObj = new QtAtomicData(); scalarDataObj->setValueType ( resultBaseType ); scalarDataObj->setValueBuffer( resultBuffer ); return scalarDataObj; } QtData* QtBinaryInduce::evaluate( QtDataList* inputList ) { QtData* returnValue = NULL; QtData* operand1 = NULL; QtData* operand2 = NULL; if( getOperands( inputList, operand1, operand2 ) ) { returnValue = computeOp( operand1, operand2 ); // delete the old operands if( operand1 ) operand1->deleteRef(); if( operand2 ) operand2->deleteRef(); } return returnValue; } const QtTypeElement& QtBinaryInduce::checkType( QtTypeTuple* typeTuple ) { RMDBCLASS( "QtBinaryInduce", "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 ); RMDBGIF( 1, RMDebug::module_qlparser, "QtBinaryInduce", \ RMInit::dbgOut << "Operand 1: " << flush; \ inputType1.printStatus( RMInit::dbgOut ); \ RMInit::dbgOut << endl; \ \ RMInit::dbgOut << "Operand 2: " << flush; \ inputType2.printStatus( RMInit::dbgOut ); \ RMInit::dbgOut << endl; \ \ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", "Operation " << opType ) \ ) if( inputType1.getDataType() == QT_MDD && inputType2.getDataType() == QT_MDD ) { const BaseType* baseType1 = ((MDDBaseType*)(inputType1.getType()))->getBaseType(); const BaseType* baseType2 = ((MDDBaseType*)(inputType2.getType()))->getBaseType(); const BaseType* resultBaseType = Ops::getResultType( opType, baseType1, baseType2 ); if( !resultBaseType ) { RMInit::logOut << "Error: QtBinaryInduce::checkType() - binary induce (MDD + MDD): operand types are incompatible." << endl; parseInfo.setErrorNo(363); throw parseInfo; } MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType ); TypeFactory::addTempType( resultMDDType ); dataStreamType.setType( resultMDDType ); } else if( inputType1.getDataType() == QT_MDD && inputType2.isBaseType() ) { const BaseType* baseType1 = ((MDDBaseType*)(inputType1.getType()))->getBaseType(); BaseType* baseType2 = (BaseType*)(inputType2.getType()); const BaseType* resultBaseType = Ops::getResultType( opType, baseType1, baseType2 ); if( !resultBaseType ) { RMInit::logOut << "Error: QtBinaryInduce::checkType() - unary induce (MDD + BaseType): operand types are incompatible." << endl; parseInfo.setErrorNo(364); throw parseInfo; } MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType ); TypeFactory::addTempType( resultMDDType ); dataStreamType.setType( resultMDDType ); } else if( inputType1.isBaseType() && inputType2.getDataType() == QT_MDD ) { BaseType* baseType1 = (BaseType*)(inputType1.getType()); const BaseType* baseType2 = ((MDDBaseType*)(inputType2.getType()))->getBaseType(); const BaseType* resultBaseType = Ops::getResultType( opType, baseType1, baseType2 ); if( !resultBaseType ) { RMInit::logOut << "Error: QtBinaryInduce::checkType() - unary induce (BaseType + MDD): operand types are incompatible." << endl; parseInfo.setErrorNo(364); throw parseInfo; } MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType ); TypeFactory::addTempType( resultMDDType ); dataStreamType.setType( resultMDDType ); } else if( inputType1.isBaseType() && inputType2.isBaseType() ) { BaseType* baseType1 = (BaseType*)(inputType1.getType()); BaseType* baseType2 = (BaseType*)(inputType2.getType()); const BaseType* resultBaseType = Ops::getResultType( opType, baseType1, baseType2 ); if( !resultBaseType ) { RMInit::logOut << "Error: QtBinaryInduce::checkType() - BaseType + BaseType : operand types are incompatible." << endl; parseInfo.setErrorNo(365); throw parseInfo; } dataStreamType.setType( resultBaseType ); } else if( inputType1.getDataType() == QT_STRING && inputType2.getDataType() == QT_STRING ) { if( opType != Ops::OP_EQUAL ) { RMInit::logOut << "Error: QtBinaryInduce::checkType() - String + String : operation is not supported on strings." << endl; parseInfo.setErrorNo(385); throw parseInfo; } dataStreamType.setDataType( QT_BOOL ); } else { RMInit::logOut << "Error: QtBinaryInduce::checkType() - operation is not supported on these data types." << endl; parseInfo.setErrorNo(403); throw parseInfo; } } else RMInit::logOut << "Error: QtBinaryInduce::checkType() - operand branch invalid." << endl; return dataStreamType; } const QtNode::QtNodeType QtPlus::nodeType = QT_PLUS; QtPlus::QtPlus( QtOperation* initInput1, QtOperation* initInput2 ) : QtBinaryInduce( initInput1, initInput2, Ops::OP_PLUS ) { } /* void QtPlus::rewriteOps() { RMDBCLASS( "QtPlus", "rewriteOps()", "qlparser", __FILE__, __LINE__ ) if( input1 && input2 ) { if( nodeType == input2->getNodeType() ) { // changed from log to debug output -- PB 2003-nov-20 RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtPlus", "rewriteOps: rule (left deep tree): A+(B+C) -> (B+C)+A" ); // more than one equal binary operator, make standard form of the tree QtBinaryOperation* nodeR = (QtBinaryOperation*) input2; QtOperation* nodeRL = nodeR->getInput1(); getParent()->setInput( this, nodeR ); nodeR->setInput1( this ); this->setInput2( nodeRL ); nodeR->rewriteOps(); } else { input1->rewriteOps(); input2->rewriteOps(); } } else RMInit::logOut << "Error: QtPlus::rewriteOps() - the operand branch is invalid." << endl; } */ /* void QtPlus::sortAssociativeOps() { ENTER( "QtPlus::sortAssociativeOps() -- input1 is " << (input1?"not null":"null") << ", input 2 is " << (input2?"not null":"null") ); if( input1 && input2 ) { if( nodeType == input1->getNodeType() ) { // associative law is applicable QtOperation* node = input1->getUniqueOrder( nodeType ); if( node && node->getSpelling().compare( input2->getSpelling() ) > 0 ) { node->getParent()->setInput( node, input2 ); setInput2( node ); } } else { bool compare = ( input1->getSpelling().compare( input2->getSpelling() ) > 0 ); TALK( "QtPlus::sortAssociativeOps(): compare -> " << compare ); if( compare ) { // changed from log to debug output -- PB 2003-nov-20 RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtPlus", "sortAssociativeOps: applying rule 'associativity'" ); QtOperation* node = input1; setInput1( input2 ); setInput2( node ); }; }; input1->sortAssociativeOps(); } else RMInit::logOut << "Error: QtPlus::sortAssociativeOps() - the operand branch is invalid." << endl; LEAVE( "QtPlus::sortAssociativeOps()" ); } */ QtOperation* QtPlus::getUniqueOrder( const QtNode::QtNodeType ID ) { RMDBCLASS( "QtPlus", "getUniqueOrder( const QtNode::QtNodeType )", "qlparser", __FILE__, __LINE__ ) QtOperation* returnValue = NULL; if( nodeType == ID ) { QtOperation* node = input1->getUniqueOrder( nodeType ); if( node ) { if( ( node->getSpelling().compare( input2->getSpelling() ) ) > 0 ) returnValue = node; else returnValue = input2; } else RMInit::logOut << "Error: QtMult::getUniqueOrder(): Query tree invalid" << endl; } else returnValue = this; return returnValue; } void QtPlus::printTree( int tab, ostream& s, QtChildType mode ) { s << SPACE_STR(tab).c_str() << "QtPlus Object " << getNodeType() << endl; QtBinaryInduce::printTree( tab, s, mode ); } void QtPlus::printAlgebraicExpression( ostream& s ) { s << "("; if( input1 ) input1->printAlgebraicExpression( s ); else s << ""; s << " + "; if( input2 ) input2->printAlgebraicExpression( s ); else s << ""; s << ")"; } const QtNode::QtNodeType QtMinus::nodeType = QT_MINUS; QtMinus::QtMinus( QtOperation* initInput1, QtOperation* initInput2 ) : QtBinaryInduce( initInput1, initInput2, Ops::OP_MINUS ) { } bool QtMinus::isCommutative() const { return false; // NOT commutative } void QtMinus::printTree( int tab, ostream& s, QtChildType mode ) { s << SPACE_STR(tab).c_str() << "QtMinus Object " << getNodeType() << endl; QtBinaryInduce::printTree( tab, s, mode ); } void QtMinus::printAlgebraicExpression( ostream& s ) { s << "("; if( input1 ) input1->printAlgebraicExpression( s ); else s << ""; s << " - "; if( input2 ) input2->printAlgebraicExpression( s ); else s << ""; s << ")"; } const QtNode::QtNodeType QtMult::nodeType = QT_MULT; QtMult::QtMult( QtOperation* initInput1, QtOperation* initInput2 ) : QtBinaryInduce( initInput1, initInput2, Ops::OP_MULT ) { } /* void QtMult::rewriteOps() { RMDBCLASS( "QtMult", "rewriteOps()", "qlparser", __FILE__, __LINE__ ) if( input1 && input2 ) { if( nodeType == input2->getNodeType() ) { RMInit::logOut << "> rule (left deep tree): A*(B*C) -> (B*C)*A" << endl; // more than one equal binary operator, make standard form of the tree QtBinaryOperation* nodeR = (QtBinaryOperation*) input2; QtOperation* nodeRL = nodeR->getInput1(); getParent()->setInput( this, nodeR ); nodeR->setInput1( this ); this->setInput2( nodeRL ); nodeR->rewriteOps(); } else { input1->rewriteOps(); input2->rewriteOps(); } } else RMInit::logOut << "Error: QtMult::rewriteOps() - the operand branch is invalid." << endl; } */ /* void QtMult::sortAssociativeOps() { RMDBCLASS( "QtMult", "sortAssociativeOps()", "qlparser", __FILE__, __LINE__ ) if( input1 && input2 ) { if( nodeType == input1->getNodeType() ) { // associative law is applicable QtOperation* node = input1->getUniqueOrder( nodeType ); if( node && node->getSpelling().compare( input2->getSpelling() ) > 0 ) { node->getParent()->setInput( node, input2 ); setInput2( node ); }; } else { if( input1->getSpelling().compare( input2->getSpelling() ) > 0 ) { RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtMult", "sortAssociativeOps: rule (associativity): A * B -> B * A" ); QtOperation* node = input1; setInput1( input2 ); setInput2( node ); }; } input1->sortAssociativeOps(); } else RMInit::logOut << "Error: QtMult::sortAssociativeOps() - the operand branch is invalid." << endl; } */ QtOperation* QtMult::getUniqueOrder( const QtNode::QtNodeType ID ) { RMDBCLASS( "QtMult", "getUniqueOrder( const string )", "qlparser", __FILE__, __LINE__ ) QtOperation* returnValue = NULL; if( nodeType == ID ) { QtOperation* node = input1->getUniqueOrder( nodeType ); if( node ) { if( node->getSpelling().compare( input2->getSpelling() ) > 0 ) returnValue = node; else returnValue = input2; } else RMInit::logOut << "Error: QtMult::getUniqueOrder(): Query tree invalid" << endl; } else returnValue = this; return returnValue; } void QtMult::printTree( int tab, ostream& s, QtChildType mode ) { s << SPACE_STR(tab).c_str() << "QtMult Object " << getNodeType() << endl; QtBinaryInduce::printTree( tab, s, mode ); } void QtMult::printAlgebraicExpression( ostream& s ) { s << "("; if( input1 ) input1->printAlgebraicExpression( s ); else s << ""; s << " * "; if( input2 ) input2->printAlgebraicExpression( s ); else s << ""; s << ")"; } const QtNode::QtNodeType QtDiv::nodeType = QT_DIV; QtDiv::QtDiv( QtOperation* initInput1, QtOperation* initInput2 ) : QtBinaryInduce( initInput1, initInput2, Ops::OP_DIV ) { } bool QtDiv::isCommutative() const { return false; // NOT commutative } void QtDiv::printTree( int tab, ostream& s, QtChildType mode ) { s << SPACE_STR(tab).c_str() << "QtDiv Object " << getNodeType() << endl; QtBinaryInduce::printTree( tab, s, mode ); } void QtDiv::printAlgebraicExpression( ostream& s ) { s << "("; if( input1 ) input1->printAlgebraicExpression( s ); else s << ""; s << " / "; if( input2 ) input2->printAlgebraicExpression( s ); else s << ""; s << ")"; }