diff options
Diffstat (limited to 'qlparser/querytree.cc')
-rw-r--r-- | qlparser/querytree.cc | 489 |
1 files changed, 489 insertions, 0 deletions
diff --git a/qlparser/querytree.cc b/qlparser/querytree.cc new file mode 100644 index 0000000..4a14ed6 --- /dev/null +++ b/qlparser/querytree.cc @@ -0,0 +1,489 @@ +/* +* 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>. +*/ +/************************************************************* + * + * SOURCE: querytree.cc + * + * MODULE: qlparser + * CLASS: QueryTree + * + * PURPOSE: + * + * COMMENTS: + * + ************************************************************/ + +static const char rcsid[] = "@(#)qlparser, QueryTree: $Id: querytree.cc,v 1.52 2005/06/28 08:42:13 rasdev Exp $"; + + +#ifndef CPPSTDLIB +#include <ospace/string.h> // STL<ToolKit> +#else +#include <string> +using namespace std; +#endif +#include <iostream> +#include <dlfcn.h> + +#include "raslib/rmdebug.hh" +#include "globals.hh" + +#include "qlparser/querytree.hh" +#include "qlparser/qtnode.hh" +#include "qlparser/qtoperationiterator.hh" +#include "qlparser/qtselectioniterator.hh" +#include "qlparser/qtjoiniterator.hh" +#include "qlparser/qtvariable.hh" +#include "qlparser/qtmdd.hh" +#include "qlparser/qtdomainoperation.hh" +#include "qlparser/qtexecute.hh" + +#include "catalogmgr/typefactory.hh" +#include "relcatalogif/mdddomaintype.hh" +#include "relcatalogif/settype.hh" + +void (*QueryTree::optimizationFnc)(unsigned int, QtNode*) = NULL; + +unsigned int QueryTree::nextCSENo = 0; + +SymbolTable<int> QueryTree::symtab; + +QueryTree::QueryTree() + : rootNode(NULL), + optimizationLevel(4) +{ +} + + +QueryTree::QueryTree( QtNode* root ) + : rootNode( root ), + optimizationLevel(4) +{ +} + + +QueryTree::~QueryTree() +{ + if( rootNode ) + { + delete rootNode; + rootNode=NULL; + } + releaseDynamicObjects(); +} + + +void +QueryTree::checkSemantics() +{ + RMDBCLASS( "QueryTree", "checkSemantics()", "qlparser", __FILE__, __LINE__ ) + + switch( rootNode->getNodeType() ) + { + case QtNode::QT_MDD_ACCESS: + case QtNode::QT_OPERATION_ITERATOR: + case QtNode::QT_JOIN_ITERATOR: + case QtNode::QT_SELECTION_ITERATOR: + { + const QtTypeTuple& resultType = ((QtONCStream*)rootNode)->checkType(); + // RMInit::logOut << "result type: " << flush; + // resultType.printStatus( RMInit::logOut ); + } + break; + + case QtNode::QT_UPDATE: + case QtNode::QT_INSERT: + case QtNode::QT_DELETE: + case QtNode::QT_COMMAND: + case QtNode::QT_PYRAMID: + ((QtExecute*)rootNode)->checkType(); + break; + + default: + { + const QtTypeElement& resultType = ((QtOperation*)rootNode)->checkType(); + // RMInit::logOut << "result type: " << flush; + // resultType.printStatus( RMInit::logOut ); + } + break; + } +} + + +void +QueryTree::optimize( unsigned int currentOptimizationLevel ) +{ + RMDBCLASS( "QueryTree", "optimize( unsigned int )", "qlparser", __FILE__, __LINE__ ) + + if (optimizationFnc == NULL) { + char *dir = CONFDIR; + char libName[255]; + sprintf(libName,"%s/lib/libqloptimizer.so", dir); + + if (access(libName, X_OK | R_OK) == 0) { + void *handle = dlopen(libName, RTLD_NOW); + if (handle == NULL) { + RMInit::logOut << "Optimization library found, however could not be loaded" << endl; + printf("DLERROR = %s\n", dlerror()); + RMInit::logOut << dlerror() << endl; + return; + } + + *(void **)(&optimizationFnc) = dlsym(handle, "runOptimizations"); + if (optimizationFnc == NULL) { + RMInit::logOut << "Optimization library found, however the entry point was not found" << endl; + return; + } + } else { + RMInit::logOut << "No optimization library found" << endl; + return; + } + } + + optimizationFnc(currentOptimizationLevel, rootNode); + + RMDBGIF( 1, RMDebug::module_qlparser, "QueryTree", \ + RMInit::logOut << endl << " "; \ + rootNode->printAlgebraicExpression( RMInit::logOut ); \ + RMInit::logOut << endl << endl; \ + rootNode->printTree( 2, RMInit::logOut ); \ + RMInit::logOut << endl; \ + ) +} + +vector<QtData*>* +QueryTree::evaluateRetrieval() throw (r_Error, ParseInfo) +{ + vector<QtData*>* returnValue=NULL; + + if( rootNode ) + { + if( rootNode->getNodeType() != QtNode::QT_MDD_ACCESS && + rootNode->getNodeType() != QtNode::QT_OPERATION_ITERATOR && + rootNode->getNodeType() != QtNode::QT_JOIN_ITERATOR && + rootNode->getNodeType() != QtNode::QT_SELECTION_ITERATOR ) + { + RMInit::logOut << "QueryTree::evaluateRetrieval() - Retrieval query must start with an ONC node." << endl; + ParseInfo errorInfo = rootNode->getParseInfo(); + errorInfo.setErrorNo(371); + throw errorInfo; + } + + QtNode::QtDataList* dataList=NULL; + QtNode::QtDataList::iterator dataIter; + QtONCStream* oncRootNode = (QtONCStream*)rootNode; + + try + { + oncRootNode->open(); + } + catch( ... ) + { + oncRootNode->close(); + RMInit::logOut << "QueryTree::evaluateRetrieval() - rethrow exception from oncRootNode->open()." << endl; + throw; + } + + // removed to have uniform, compact log output -- PB 2003-nov-20 + // RMInit::logOut << endl; + + // create result collection + vector<QtData*>* resultData = new vector<QtData*>(); + + try + { + while( (dataList = oncRootNode->next()) ) + { + if( dataList->size() > 1 || (*dataList)[0] == NULL ) + { + // Delete the tupel vector received by next(). Just tupel elements which are not + // further referenced are deleted. + for( dataIter=dataList->begin(); dataIter!=dataList->end(); dataIter++ ) + if( *dataIter ) (*dataIter)->deleteRef(); + delete dataList; + dataList=NULL; + + if( resultData ) + { + // Delete the result vector + for( dataIter=resultData->begin(); dataIter!=resultData->end(); dataIter++ ) + if( *dataIter ) (*dataIter)->deleteRef(); + delete resultData; + resultData = NULL; + } + + RMInit::logOut << "QueryTree::evaluateTree() - multiple query targets are not supported." << endl; + ParseInfo errorInfo = oncRootNode->getParseInfo(); + errorInfo.setErrorNo(361); + throw errorInfo; + } + + QtData* resultElement = (*dataList)[0]; + + // take the data element as result data and reset it in the tupel vector + resultData->push_back( resultElement ); + (*dataList)[0] = NULL; + + RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QueryTree", endl << endl << "NEXT RESULT ITEM OF THE QUERY INSERTED" << endl << endl ) + + // Delete the tupel vector received by next(). Just tupel elements which are not + // set to zero and which are not further referenced are deleted. + for( dataIter=dataList->begin(); dataIter!=dataList->end(); dataIter++ ) + if( *dataIter ) (*dataIter)->deleteRef(); + + // delete the tuple vector + delete dataList; + dataList=NULL; + } + } + catch(r_Error& myErr) { + RMInit::logOut << endl << "Caught BAD exception when evaluating query! " << endl; + RMInit::logOut << myErr.what() << endl; + if( resultData ) + { + // Delete the result vector + for( dataIter=resultData->begin(); dataIter!=resultData->end(); dataIter++ ) + if( *dataIter ) (*dataIter)->deleteRef(); + delete resultData; + resultData = NULL; + } + + oncRootNode->close(); + RMInit::logOut << "QueryTree::evaluateTree() - rethrow exception." << endl; + throw; + } + catch( ... ) + { + if( resultData ) + { + // Delete the result vector + for( dataIter=resultData->begin(); dataIter!=resultData->end(); dataIter++ ) + if( *dataIter ) (*dataIter)->deleteRef(); + delete resultData; + resultData = NULL; + } + + oncRootNode->close(); + RMInit::logOut << "QueryTree::evaluateTree() - rethrow exception." << endl; + throw; + } + + oncRootNode->close(); + + returnValue = resultData; + } + + return returnValue; +} + + + +void +QueryTree::evaluateUpdate() throw (r_Error,ParseInfo) +{ + if( rootNode ) + { + if( rootNode->getNodeType() != QtNode::QT_UPDATE && + rootNode->getNodeType() != QtNode::QT_INSERT && + rootNode->getNodeType() != QtNode::QT_DELETE && + rootNode->getNodeType() != QtNode::QT_COMMAND && + rootNode->getNodeType() != QtNode::QT_PYRAMID + ) + { + RMInit::logOut << "QueryTree::evaluateUpdate() - update query must start with an INSERT, UPDATE, DELETE, DROP or CREATE statement." << endl; + ParseInfo errorInfo = rootNode->getParseInfo(); + errorInfo.setErrorNo(372); + throw errorInfo; + } + + QtExecute* executeNode = (QtExecute*) rootNode; + + // evaluate the update query + executeNode->evaluate(); + } +} + + + +void QueryTree::printTree( int tab, ostream& s ) { + if ( rootNode ) { + s << SPACE_STR(tab).c_str() << "QueryTree:" << endl; + rootNode->printTree( tab + 2, s ); + } else + s << SPACE_STR(tab).c_str() << "QueryTree: Qt has no root node." << endl; +} + +void QueryTree::addDynamicObject( QtNode *node ) { + qtNodeList.push_back( node ); +} + +void QueryTree::removeDynamicObject( QtNode *node ) { + qtNodeList.remove( node ); +} + +void QueryTree::addDynamicObject( QtData *node ) { + qtDataList.push_back( node ); +} + +void QueryTree::removeDynamicObject( QtData *node ) { + qtDataList.remove( node ); +} + +void QueryTree::addDynamicObject( ParseInfo *node ) { + parseInfoList.push_back( node ); +} + +void QueryTree::removeDynamicObject( ParseInfo *node ) { + parseInfoList.remove( node ); +} + +void QueryTree::addDynamicObject( vector<QtONCStream *> *node ) { + vectorList.push_back( node ); +} + +void QueryTree::removeDynamicObject( vector<QtONCStream*> *node ) { + vectorList.remove( node ); +} + +void QueryTree::releaseDynamicObjects() { + list<QtNode*>::iterator iter1; + for( iter1 = qtNodeList.begin(); iter1 != qtNodeList.end(); iter1++ ) + { + delete *iter1; + *iter1=NULL; + } + + list<QtData*>::iterator iter2; + for( iter2 = qtDataList.begin(); iter2 != qtDataList.end(); iter2++ ) + { + delete *iter2; + *iter2=NULL; + } + + list<ParseInfo*>::iterator iter3; + for( iter3 = parseInfoList.begin(); iter3 != parseInfoList.end(); iter3++ ) + { + delete *iter3; + *iter3=NULL; + } + + list<vector<QtONCStream*>*>::iterator iter4; + for( iter4 = vectorList.begin(); iter4 != vectorList.end(); iter4++ ) + { + delete *iter4; + *iter4=NULL; + } + + list<char *>::iterator iter5; + for( iter5 = lexedCStringList.begin(); iter5 != lexedCStringList.end(); iter5++ ) + { + free(*iter5); + *iter5=NULL; + } +} + +void QueryTree::addDomainObject( QtDomainOperation *dop ) { + dopList.push_back( dop ); +} + +void QueryTree::removeDomainObject( QtDomainOperation *dop ) { + dopList.remove( dop ); +} + +void QueryTree::printDomainObjects() { + list<QtDomainOperation*>::iterator iter; + for( iter = dopList.begin(); iter != dopList.end(); iter++ ) { + cout << endl; + (*iter)->printTree( 2 ); + } +} + +void QueryTree::releaseDomainObjects() { + list<QtDomainOperation*>::iterator iter; + for( iter = dopList.begin(); iter != dopList.end(); iter++ ) + { + delete *iter; + *iter=NULL; + } +} + +void QueryTree::rewriteDomainObjects(r_Minterval *greatDomain, string *greatIterator, QtMarrayOp2::mddIntervalListType *greatList) { + + RMDBGENTER( 2, RMDebug::module_qlparser, "QueryTree", endl << "QueryTree: Iterator: <" << *greatIterator << "> Domain: " << *greatDomain << endl ) + list<QtDomainOperation*>::iterator iter; + + for( iter = dopList.begin(); iter != dopList.end(); iter++ ) { + + // 1. get var name from iter + QtVariable *qtVar = ((QtVariable *)((*iter)->getInput())); + string stVar = qtVar->getIteratorName(); + const char *varname = stVar.c_str(); + + // 2. get position of varname in varList + bool bcond = false; + QtMarrayOp2::mddIntervalListType *varList = greatList; + QtMarrayOp2::mddIntervalListType::iterator varIter; + r_Long varpos = 0; + for (varIter = varList->begin(); varIter != varList->end(); varIter++) { + + if (!strcmp(varname, varIter->variable.c_str())) { + bcond = true; + break; + }; + QtData *data = varIter->tree->evaluate(0); + r_Dimension dimension = ((QtMintervalData*)data)->getMintervalData().dimension(); + varpos = varpos+dimension; + }; + // postcond: bcond == false: varname not found in list. else varpos gives the position. + + if (bcond) { + + // 3. set domain expression to old one incremented by varpos + QtNode::QtOperationList *lop = new QtNode::QtOperationList(1); + (*lop)[0] = + new QtPlus( + (*iter)->getMintervalOp(), + new QtConst( + new QtAtomicData( + varpos, sizeof(varpos) + ) + ) + ); + + (*iter)->setMintervalOp( new QtPointOp( lop ) ); + + // 4. set varname to greatIterator + QtVariable *var1 = new QtVariable( string(*greatIterator) ); + (*iter)->setInput(var1); + + } else + { + // TODO: insert some error notify code here! + RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QueryTree", " variable name not found in list " ) + } + } +} + +void QueryTree::addCString( char *str ) { + lexedCStringList.push_back( str ); +} |