///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoSelect.cc
// -------------
// Cego query implementation         
//     
// Design and Implementation by Bjoern Lemke
//     
// (C)opyright 2000-2012 Bjoern Lemke
//
// This program 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 2, or (at your option)
// any later version.
// 
// This program 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 this program; see the file COPYING.  If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
//
// IMPLEMENTATION MODULE
//
// Class: CegoSelect
// 
// Description: 
//
// Status: QS-2.6
//
///////////////////////////////////////////////////////////////////////////////

// base includes
#include <lfc/Datetime.h>
#include <lfc/SetT.h>

// cego includes
#include "CegoSelect.h"
#include "CegoQueryHelper.h"
#include "CegoCaseCond.h"
#include "CegoJoinObject.h"
#include "CegoXMLdef.h"

#include <string.h>
#include <stdlib.h>

CegoSelect::CegoSelect(char* buf, CegoDistManager* pGTM)
{
    decode(buf, pGTM);
}

CegoSelect::CegoSelect(Element* pSelectElement, CegoDistManager* pGTM)
{
    _pPred = 0;
    _pHaving = 0;
    _pNativeOrderList = 0;
    _pOrderList = 0;
    _pGroupList = 0;
    _pNativeOrderOptList = 0;
    _pOrderOptList = 0;
    _pOrderSpace = 0;
    _pGroupSpace = 0;
    _pGTM = 0;
    _pLogger = 0;
    _modId = 0;

    int i=0;
    while ( i < TABMNG_MAXJOINLEVEL )
    {
	_pTC[i]=0;
	_attrCondFlag[i] = false;
	_firstTuple[i]=true;
	_attrPred[i]=0;
	i++;
    }
    
    _pBlock = 0;
    _pUnionSelect = 0;

    _checkUnion = false;
    _selectMode = PLAIN;
    _nextAid=0;
    _aggregationCount=0;

    _pOrderCursor=0;
    _pGroupCursor=0;

    _isDistinct = false;
    _pParentJoinBuf = 0;
    _tabSetId = 0;
    _isPrepared = false;
    _rowLimit = 0;
    _doCaching = false;
    _isCached = false;
    _extRefCount = 0;

    _cacheEnabled = true;

    fromElement(pSelectElement, pGTM);
}

CegoSelect::CegoSelect(ListT<CegoContentObject*>& coList,
		       ListT<CegoExpr*>& exprList, 
		       CegoPredDesc* pPred,
		       ListT<CegoAttrDesc*> *pGroupList,
		       CegoHavingDesc* pHaving,
		       ListT<CegoExpr*> *pOrderList,
		       ListT<CegoOrderNode::Ordering>* pOrderOptList,
		       bool isDistinct,
		       int rowLimit,
		       CegoDistManager* pGTM)
{
    _coList = coList;
    _exprList = exprList;
    _pPred = pPred;
    _pGroupList = pGroupList;
    _pHaving = pHaving;
    _pNativeOrderList = pOrderList;
    _pOrderList = 0;
    _pNativeOrderOptList = pOrderOptList;
    _pOrderOptList = 0;
    _pOrderSpace = 0;
    _pGroupSpace = 0;
    _pGTM = pGTM;
    _pLogger = _pGTM->getDBMng();
    _modId = _pGTM->getDBMng()->getModId("CegoSelect");

    int i=0;
    while ( i < TABMNG_MAXJOINLEVEL )
    {
	_pTC[i]=0;
	_attrCondFlag[i] = false;
	_firstTuple[i]=true;
	_attrPred[i]=0;
	i++;
    }
    
    _pBlock = 0;
    _pUnionSelect = 0;

    _checkUnion = false;
    _selectMode = PLAIN;
    _nextAid=0;
    _aggregationCount=0;

    _pOrderCursor=0;
    _pGroupCursor=0;

    _isDistinct = isDistinct;
    _pParentJoinBuf = 0;
    _tabSetId = 0;
    _isPrepared = false;
    _rowLimit = rowLimit;
    _doCaching = false;
    _isCached = false;

    _cacheEnabled = true;

    _orderingDone=false;
    _groupingDone=false;

    _extRefCount = 0;
}

CegoSelect::~CegoSelect()
{

    if ( _pPred )
	delete _pPred;

    CegoPredDesc **pP = _viewConjunctionList.First();
    while ( pP )
    {      
	delete (*pP);
	pP = _viewConjunctionList.Next();
    }
    
    int i=0;
    while ( i < TABMNG_MAXJOINLEVEL )
    {
	if ( _pTC[i] )
	    delete _pTC[i];
	i++;
    }    

    CegoContentObject **pCO = _coList.First();
    while ( pCO )
    {
	delete (*pCO);
	pCO = _coList.Next();
    }

    CegoExpr **pExpr = _exprList.First();
    while ( pExpr )
    {
	delete (*pExpr);
	pExpr = _exprList.Next();
    }

    if ( _pOrderList )
    {
	if ( _pOrderCursor )
	    delete _pOrderCursor;
	if ( _pOrderSpace )
	{
	    delete _pOrderSpace;	
	    _pOrderSpace = 0;
	}

	CegoExpr **pExpr = _pOrderList->First();
	while ( pExpr )
	{
	    delete (*pExpr);
	    pExpr = _pOrderList->Next();
	}

	delete _pOrderList;
	_pOrderList = 0;
	
    }

    if ( _pNativeOrderList )
    {
	CegoExpr **pExpr = _pNativeOrderList->First();
	while ( pExpr )
	{
	    delete (*pExpr);
	    pExpr = _pNativeOrderList->Next();
	}

	delete _pNativeOrderList;
	_pNativeOrderList = 0;	
    }

    if ( _pGroupList )
    {
	
	if ( _pGroupCursor )
	    delete _pGroupCursor;
	if ( _pGroupSpace )
	{
	    delete _pGroupSpace;
	    _pGroupSpace=0;
	}

	CegoAttrDesc **pAttrDesc = _pGroupList->First();
	while ( pAttrDesc )
	{
	    delete (*pAttrDesc);
	    pAttrDesc = _pGroupList->Next();
	}
	
	delete _pGroupList;
	_pGroupList = 0;
    }
    
    if ( _pGTM )
	_pGTM->setAllocatedSortArea(0);

    if ( _pHaving )
    {
	delete _pHaving;
    }
    
    if ( _pUnionSelect )
    {
	delete _pUnionSelect;
    }

}

void CegoSelect::setTableManager(CegoDistManager* pGTM)
{
    _pGTM = pGTM;
    _pLogger = _pGTM->getDBMng();
    _modId = _pGTM->getDBMng()->getModId("CegoSelect"); 	
}

// the cleanup method makes a complete reinitialization of the select statement to the state
// after the instance has been created

void CegoSelect::cleanUp()
{

    _conjunctionList.Empty();
    _joinList.Empty();
    _joinPredList.Empty();

    _joinFields.Empty();
    _aggregationCount=0;
    _nextAid=0;
    
    int i = 0;
    while ( i < TABMNG_MAXJOINLEVEL )
    {	
	if ( _pTC[i] )
	    delete _pTC[i];
	_pTC[i]=0;

	_attrCondFlag[i] = false;
	_firstTuple[i]=true;
	_attrPred[i]=0;
	i++;
    }

    // cleanup
    if ( _pPred )
    {
	_pPred->setCheckedRec(false);
	_pPred->cleanUp();
	_pPred->clearAttrCache();
    }
    
    _isPrepared = false;

    _checkUnion = false;

    if ( _pUnionSelect )
    {
	_pUnionSelect->cleanUp();
    }

    if ( _pOrderSpace )
    {
	_pOrderSpace->resetOrderSpace();
    }

    _orderingDone=false;

    if ( _pGroupList )
    {
	_groupingDone = false;
		
	if ( _pGroupSpace )
	    _pGroupSpace->resetGroupSpace();
	
    }
    
    _isCached = false;
    _queryCache.Empty();

}

// the prepare method organizes the select query parameters in a kind,
// that the join can be performed in the best way. This requires evaluating 
// of all attribute references and evaluation of the join condition to build
// an appropriate join table order list.
// the method detects, if the join was already prepared and if so, it just adjuts 
// changed join parameters ( e.g. contained procedure or parent query variables ) to the appropriate value

void CegoSelect::prepare() 
{

    if ( _isPrepared )
    {
#ifdef CGDEBUG
	_pLogger->log(_modId, Logger::DEBUG, Chain("Building join conditions ..."));
#endif
	buildJoinConditions();
	return;
    }
        
#ifdef CGDEBUG
    _pLogger->log(_modId, Logger::DEBUG, Chain("Evaluating references ..."));	
#endif

    evalReferences();
    
#ifdef CGDEBUG
    _pLogger->log(_modId, Logger::DEBUG, Chain("Analyzing join ..."));	
#endif

    analyzeJoin();

#ifdef CGDEBUG
    _pLogger->log(_modId, Logger::DEBUG, Chain("Making order ..."));	
#endif

    makeOrder();

    if ( _selectMode == AGGREGATION )
	_aggDone=false;
        
    if ( _pGroupList )
    {
	_groupingDone = false;

	if ( _pGroupSpace == 0 )
	    _pGroupSpace = new CegoGroupSpace();
	else
	    _pGroupSpace->resetGroupSpace();

	if ( _selectMode == AGGREGATION )
	    _selectMode = GROUPING;
	else
	    throw Exception(EXLOC, "Missing aggregation for group clause");
    }
    
    if ( _pOrderList )
    {
	_orderingDone=false;
	if ( _pOrderSpace == 0 )
	    _pOrderSpace = new CegoOrderSpace();
	else
	    _pOrderSpace->resetOrderSpace();	    
    }
    
    _rowCount=0;

    // Last but not least, clear the attribute cache for all attributes
    
    CegoPredDesc **pPred = _conjunctionList.First();
    while ( pPred )
    {
        (*pPred)->clearAttrCache();
        pPred = _conjunctionList.Next();
    }
    if (_pPred)
    {
       _pPred->clearAttrCache();
    }

    CegoExpr **pExpr = _exprList.First();
    while ( pExpr )
    {
        (*pExpr)->clearAttrCache();
        pExpr = _exprList.Next();
    }

    if ( _pHaving )
    {
	_pHaving->getExpr()->clearAttrCache();
	_pHaving->getAggExpr()->clearAttrCache();	
    }

    
    if ( _pOrderList )
    {
	pExpr = _pOrderList->First();
	while ( pExpr )
	{
	    (*pExpr)->clearAttrCache();
	    pExpr = _pOrderList->Next();
	}
    }
    
    // end of cache clear

    _isPrepared = true;

    if ( _pUnionSelect )
    {
	_pUnionSelect->prepare();
    }    
}

// the reset method performas a reset on the query without making any join evaluation
// actions. This method can be used, if there was no change on any included join variables
// 

void CegoSelect::reset(bool doRelease)
{
    _joinLevel=0;
    _joinSize=0;

    if ( _selectMode == AGGREGATION )
	_aggDone=false;

    int i=0;
    while ( i < TABMNG_MAXJOINLEVEL )
    {
	_firstTuple[i]=true;
	i++;
    }
    i=0;
    while ( i < TABMNG_MAXJOINLEVEL )
    {
	if ( _pTC[i] )
	{
	    _pTC[i]->reset();
	    if ( doRelease )
	    {
		delete _pTC[i];
		_pTC[i] = 0;
	    }
	}
	i++;
    }

    if ( _pUnionSelect )
    {
	_checkUnion = false;
	_pUnionSelect->reset(doRelease);
    }
    
    if ( _doCaching )
    {
	if ( _isCached )
	{
	    _firstFromCache = true;
	}
	else
	{
	    // if caching is enabled, but not completely filled,
	    // we clear cache to avoid duplicate cache entries
	    _queryCache.Empty();
	}
    }
    
    if ( _pOrderSpace )
    {
	_pOrderSpace->resetOrderSpace();
    }

    if ( _pPred )
    {
	_pPred->clearAttrCache();
    }

    _orderingDone=false;
   
}

void CegoSelect::setUnionSelect(CegoSelect* pUnion)
{
    _pUnionSelect = pUnion;
}

bool CegoSelect::isPrepared() const
{
    return _isPrepared;
}


// the analyzeJoin method builds up a join strategy in terms of  
// creating a join order and filtering all required join attributes
// Depending on the analyzed join where condition, a table access plan 
// is created ( either index optimized or  full table scan )
// This also involves join optimization for underlying subqueries
void CegoSelect::analyzeJoin()
{

    
#ifdef CGDEBUG
    _pLogger->log(_modId, Logger::DEBUG, Chain("Preparing join ..."));	
#endif    

    if (_pPred)
    {   
	if (_pPred->getCondition())
	{
	    CegoQueryHelper queryHelper;
	    queryHelper.makeCNF(_pPred->getCondition());
	}

	createConjunctionList(_pPred);
	
    }

    _conjunctionList += _viewConjunctionList;
    
#ifdef CGDEBUG
    _pLogger->log(_modId, Logger::DEBUG, Chain("Consolidating conjunction list ..."));
#endif    

    consolidateConjunctionList();
    
#ifdef CGDEBUG
    _pLogger->log(_modId, Logger::DEBUG, Chain("Building join tables ..."));
#endif

    buildJoinTables();

#ifdef CGDEBUG    
    _pLogger->log(_modId, Logger::DEBUG, Chain("Building join refs ..."));
#endif

    buildJoinRefs();

#ifdef CGDEBUG
    _pLogger->log(_modId, Logger::DEBUG, Chain("Building join cursor conditions ..."));
#endif

    buildJoinConditions();

    _joinLevel = 0;
    _joinSize = 0;
    

    // prepare sub queries
    if ( _pPred ) 
    {
#ifdef CGDEBUG
	_pLogger->log(_modId, Logger::DEBUG, Chain("Analyzing subselect ..."));
#endif
	ListT<CegoSelect*> queryList;
	_pPred->getSelectQueryList(queryList);
	
	CegoSelect **pSelect = queryList.First();
	while ( pSelect )
	{
	    (*pSelect)->setParentJoinBuf(&_joinFields, 1);
	    pSelect = queryList.Next();
	}

	_pPred->analyzeSelect();
    }

#ifdef CGDEBUG
    _pLogger->log(_modId, Logger::DEBUG, Chain("Select prepared"));
#endif

}

Element* CegoSelect::getPlan()
{

    Element *pPlan = new Element(XML_PLAN_ELEMENT);

    int joinLevel=0;
    while ( joinLevel < _joinList.Size() )
    {

#ifdef CGDEBUG	
	_pLogger->log(_modId, Logger::DEBUG, Chain("Creating cursor for ") + _joinList[joinLevel]->getTabName());
#endif	

	_pTC[joinLevel] = 
	    new CegoDistCursor(_pGTM,_joinList[joinLevel]);

	_pTC[joinLevel]->checkType();
	
	if ( _attrCondFlag[joinLevel] == true )
	{

#ifdef CGDEBUG	    
	    _pLogger->log(_modId, Logger::DEBUG, Chain("Setting attrcond =  ") + _attrCond[joinLevel].toChain());
#endif

	    if ( _attrCond[joinLevel].setup(_joinBuf, 0, _joinSize ) == false )
	    {
		// attribute condition can not be resolved on this join level
		// for this reason, we disable for the future
		// since this condition is disabled, we also have to enable predicate check again
		// for the final evaluation
		
		_attrCondFlag[joinLevel]=false;
		if ( _attrPred[joinLevel] )
		{
		    _attrPred[joinLevel]->setChecked(false);
		}
	    }	    
	 
	    _pTC[joinLevel]->distSetup(_attrCond[joinLevel]);

	}
	else
	{
	    _pTC[joinLevel]->distSetup();
	}
	
	Element* pCursorPlan = _pTC[joinLevel]->getPlan();
	
	pPlan->addContent(pCursorPlan);
	
	joinLevel++;
    }
    
    
    ListT<Element*> planList;
    
    CegoExpr **pExpr = _exprList.First();
    while ( pExpr )
    {
	
	(*pExpr)->setFieldListArray( _joinBuf, _joinSize  );
	
	(*pExpr)->getPlanList(planList);
	pExpr = _exprList.Next();
    }
    
    if ( _pPred ) 
    {	
	_pPred->getPlanList(planList);    
    }

    Element** pSubPlan = planList.First();
    while ( pSubPlan )
    {
	pPlan->addContent(*pSubPlan);	
	pSubPlan = planList.Next();
    }

    if ( _pUnionSelect )
    {
	pPlan->addContent(_pUnionSelect->getPlan());
    }    

 
    return pPlan;
}

void CegoSelect::setParentJoinBuf(ListT<CegoField>* pParentJoinBuf, int size)
{
    _pParentJoinBuf = pParentJoinBuf;
    _parentJoinBufSize = size;
    
    if ( _pUnionSelect )
    {
	_pUnionSelect->setParentJoinBuf(pParentJoinBuf, size);
    }

}

void CegoSelect::checkValidRef()
{
   
#ifdef CGDEBUG
    _pLogger->log(_modId, Logger::DEBUG, Chain("Validating references ..."));
#endif

    ListT<CegoAttrDesc*> attrRefList = getAttrRefList();
    CegoAttrDesc **pAD = attrRefList.First();
    while ( pAD )
    {	
	if ( (*pAD)->isValid() == false )
	{
	    throw Exception(EXLOC, Chain("Unknown attribute ") + (*pAD)->toChain()); 
	}

#ifdef CGDEBUG
	_pLogger->log(_modId, Logger::DEBUG, Chain("Validated attribute reference ") + (*pAD)->toChain());
#endif

	pAD = attrRefList.Next();
    }
}

void CegoSelect::setProcBlock(CegoProcBlock *pBlock)
{
    _pBlock = pBlock;

    CegoExpr** pExpr = _exprList.First();
    while (pExpr)
    {
	(*pExpr)->setBlock(_pBlock);	    
	pExpr = _exprList.Next();
    }

    if ( _pUnionSelect )
    {
	_pUnionSelect->setProcBlock(pBlock);
    }
}

bool CegoSelect::nextTuple(ListT<CegoField>& jfl)
{

    if ( _rowLimit > 0 && _rowCount >= _rowLimit )
	return false;
    else
	_rowCount++;

    if ( _doCaching && _isCached )
    {
	ListT<CegoField>* pFL;
	if ( _firstFromCache )
	{
	    pFL = _queryCache.First();
	    _firstFromCache = false;
	}
	else
	{
	    pFL = _queryCache.Next();
	}

	if ( pFL )
	{
	    jfl = *pFL;
	    return true;
	}
	_firstFromCache = true;
	return false;
    }
    else
    {	
	
	if ( _checkUnion == false )
	    if ( nextAggTuple(jfl) )
	    {
		if ( _doCaching )
		{
		    _queryCache.Insert(jfl);
		}
		return true;
	    }
	
	if ( _pUnionSelect )
	{
	    _checkUnion = true;

	    jfl.Empty();
	    if ( _pUnionSelect->nextTuple(jfl) )
	    {
		if ( _doCaching )
		    _queryCache.Insert(jfl);
		return true;
	    }
	}

	if ( _doCaching )
	{
	    _isCached = true;
	    _firstFromCache = true;
	}
	return false;
    }
}

void CegoSelect::setCaching(bool doCaching)
{
    if ( _extRefCount == 0 && _cacheEnabled )
    {
	_doCaching = doCaching;       
    }	
}

bool CegoSelect::isCaching()
{
    return _doCaching;
}

bool CegoSelect::isCached()
{
    return _isCached;
}

void CegoSelect::enableCache()
{
    _cacheEnabled = true;
}

void CegoSelect::disableCache()
{
    _cacheEnabled = false;
}

bool CegoSelect::isCacheEnabled()
{
    return _cacheEnabled;
}

bool CegoSelect::nextAggTuple(ListT<CegoField>& jfl)
{
    if ( _selectMode == AGGREGATION )
    {
	if ( _aggDone )
	    return false;
	bool moreTuple=true;

	initAggregation();

	while ( moreTuple )
	{
	    ListT<CegoField> aggTuple;
	    moreTuple = nextOrderedTuple(aggTuple);
	    
	    if ( moreTuple )
	    {
		aggregateTuple(aggTuple);
		_aggregationCount++;
	    }	    
	}
	
	evalAggregation(jfl);
	
	_aggDone=true;
	return true;
    }
    else
    {
	return nextOrderedTuple(jfl);
    }
}

bool CegoSelect::nextOrderedTuple(ListT<CegoField>& jfl)
{
    if ( _pGTM == 0 )
	throw Exception(EXLOC, "No tablemanager set");

    if ( _pOrderList )
    {
	if ( _orderingDone )
	{
	    jfl = _orderedSchema;

	    if ( _isDistinct )
	    {
		
		while ( _pOrderCursor->getNext(jfl) )
		{
		    CegoField* pF1=_dfl.First();
		    CegoField* pF2=jfl.First();
		    int i=0;
		    while ( pF1 && pF2 && i < _dcount )
		    {
			if ( pF1->getValue() != pF2->getValue() )
			{
			    _dfl = jfl;
			    return true;
			}
			i++;
			pF1=_dfl.Next();
			pF2=jfl.Next();
		    }
		}
		return false;
	    }
	    else
	    {
		return _pOrderCursor->getNext(jfl);
	    }
	}
	else
	{
	    ListT<CegoField> dataTuple;
	    ListT<CegoField> orderTuple;
	    bool isInit=false;

	    while ( nextResultTuple(dataTuple, orderTuple) )
	    {		

		//_pLogger->log(_modId, Logger::DEBUG, Chain("Collect next order tuple ..."));	    
		ListT<CegoField> orderKey;

		CegoExpr **pExpr = _pOrderList->First();
		while ( pExpr )
		{	
		    ListT<CegoAttrDesc*> attrRefList = (*pExpr)->getAttrRefList();

		    CegoAttrDesc** pAttrRef = attrRefList.First();

		    while ( pAttrRef )
		    {
			if ( CegoField* pF = orderTuple.Find(CegoField((*pAttrRef)->getTableName(), (*pAttrRef)->getAttrName())) )
			{
			    orderKey.Insert(*pF);
			}
			pAttrRef = attrRefList.Next();
		    }

		    // _pLogger->log(_modId, Logger::DEBUG, Chain("Checking aggregation..."));
		    // check for aggregation id
		    ListT<CegoAggregation*> aggList = (*pExpr)->getAggregationList();
		    CegoAggregation **pAgg = aggList.First();
		    
		    while ( pAgg )
		    {
			bool notFound = true;
			CegoField* pF = orderTuple.First();
			while ( pF && notFound )
			{
			    if ( pF->getId() == (*pAgg)->getAggregationId() )
			    {
				orderKey.Insert(*pF);
				notFound = false;
			    }
			    else
			    {
				pF = orderTuple.Next();
			    }
			}
			
			if ( notFound )
			{
			    Chain msg = Chain("Unknown order expression ") +  (*pAgg)->toChain();
			    throw Exception(EXLOC, msg);
			}
			pAgg = aggList.Next();				
		    }			    
		    pExpr = _pOrderList->Next();
		}

		if ( isInit == false )
		{

		    // _pLogger->log(_modId, Logger::DEBUG, Chain("Creating order space..."));
		    // _orderSpace = Chain(OSPACE) + Chain(oid);		    
		    _pOrderSpace->initOrderSpace(_pOrderList, _pOrderOptList,  _pGTM->getDBMng()->getSortAreaSize(_tabSetId));
		}

		// _pLogger->log(_modId, Logger::DEBUG, Chain("Insert order tuple..."));
		_pOrderSpace->insertTuple(orderKey, dataTuple);
		if ( _pGroupSpace )
		    _pGTM->setAllocatedSortArea(_pOrderSpace->numAllocated() + _pGroupSpace->numAllocated());
		else
		    _pGTM->setAllocatedSortArea(_pOrderSpace->numAllocated());

		if ( isInit == false )
		{    
		    _orderedSchema = dataTuple;
		    isInit=true;
		}

	    }

	    // no rows were selected
	    if ( isInit == false )
	    {
		return false;
	    }

	    // _pLogger->log(_modId, Logger::DEBUG, Chain("Ordering done"));
	    _orderingDone = true;
	    
	    if ( _pOrderCursor )
		delete _pOrderCursor;
	    
	    _pOrderCursor = _pOrderSpace->getCursor();
	    
	    jfl = _orderedSchema;

	    bool moreTuple = _pOrderCursor->getFirst(jfl); 

	    if ( _isDistinct )
		_dfl = jfl;
	    return moreTuple;

	}
    }
    else
    {
	ListT<CegoField> ofl;
	return nextResultTuple(jfl, ofl);
    }
}

// the nextResultTuple method is used as a cursor to retrieve the corresponding result set of 
// the defined select query. the method returns true until no further tuple results are
// returned from the query. The current tuple result is provided in the reference parameter jfl

bool CegoSelect::nextResultTuple(ListT<CegoField>& jfl, ListT<CegoField>& ofl)
{
    
    switch ( _selectMode )
    {
    case PLAIN:
    case AGGREGATION:
    {
	return nextJoinTuple(jfl, ofl);
    }
    case GROUPING:
    {
	
	ListT<CegoField> gfl = jfl;

	bool moreTuple = nextGroupedTuple(gfl);

	ofl=gfl;

	if ( moreTuple == false )
	    return false;

	jfl.Empty();
	CegoExpr **pExpr = _exprList.First();
	while ( pExpr )
	{

	    ListT<CegoAggregation*> aggList;	    
	    aggList = (*pExpr)->getAggregationList();
	    
	    if ( aggList.Size() > 0 ) 
	    {
		CegoField f;

		CegoAggregation **pAgg = aggList.First();
		while ( pAgg )
		{
		    bool notFound=true;
		    CegoField *pF = gfl.First();
		    while ( pF && notFound )
		    {
			if ( pF->getId() == (*pAgg)->getAggregationId() )
			{
			    (*pAgg)->setFieldValue(pF->getValue());
			    f.setId((*pAgg)->getAggregationId());
			    notFound=false;
			}			    
			pF = gfl.Next();
		    }		
		    pAgg = aggList.Next();
		}
		
		(*pExpr)->setFieldListArray( &gfl, 1);
		f.setValue ( (*pExpr)->evalFieldValue() );
		f.setAttrName((*pExpr)->getAlias());
		jfl.Insert(f);
	    }
	    else
	    {
		CegoField f;
		f.setId(0);
		(*pExpr)->setFieldListArray( &gfl, 1);
		f.setValue((*pExpr)->evalFieldValue() );
		f.setAttrName((*pExpr)->getAlias());
		jfl.Insert(f);
	    }
	    pExpr = _exprList.Next();
	}
	
	return moreTuple;
    }
    }
}

bool CegoSelect::nextGroupedTuple(ListT<CegoField>& jfl)
{

    if ( _groupingDone )
    {
	jfl = _pGroupSpace->getSchema();

	if ( _pHaving )
	{
	    while ( _pGroupCursor->getNext(jfl) )
	    {
		_pHaving->getExpr()->setFieldListArray(&jfl, 1);
		_pHaving->getAggExpr()->setFieldListArray(&jfl, 1);
		
		setAggregationValue(_pHaving->getExpr(), jfl);
		setAggregationValue(_pHaving->getAggExpr(), jfl);
		
		if ( matchFieldValue(_pHaving->getAggExpr()->evalFieldValue(),
				     _pHaving->getExpr()->evalFieldValue(), 
				     _pHaving->getComparison()))
		{
		    return true;
		}
	    }
	    return false;
	}
	else
	{
	    return _pGroupCursor->getNext(jfl);
	}
    }
    else
    {
	
	ListT<CegoAggregation*> aggList;

	CegoExpr** pExpr = _exprList.First();
	while ( pExpr )
	{	    	    
	    aggList += (*pExpr)->getAggregationList();
	    pExpr = _exprList.Next();
	}
	if ( _pHaving )
	{
	    aggList += _pHaving->getAggExpr()->getAggregationList();
	    aggList += _pHaving->getExpr()->getAggregationList();	    
	}

	if ( _pOrderList )
	{
	    CegoExpr **pExpr = _pOrderList->First();
	    while ( pExpr )
	    {
		aggList += (*pExpr)->getAggregationList();
		pExpr = _pOrderList->Next();
	    }
	}
	
	ListT<CegoField> dataTuple;
	bool isInit=false;

	ListT<CegoField> ofl;
	while ( nextJoinTuple(dataTuple, ofl) )
	{		
	    ListT<CegoField> groupKey;
	    CegoAttrDesc** pAttrRef = _pGroupList->First();
		
	    while ( pAttrRef )
	    {
		CegoField* pF;
		if ( (pF = dataTuple.Find(CegoField((*pAttrRef)->getTableName(), (*pAttrRef)->getAttrName()))) != 0 )
		{
		    groupKey.Insert(*pF);
		}
		else
		{
		    Chain msg = Chain("Unknown group attribute ") +  (*pAttrRef)->getTableName() + Chain(".") + (*pAttrRef)->getAttrName();
		    throw Exception(EXLOC, msg);
		}
		pAttrRef = _pGroupList->Next();
	    }

	    if ( isInit == false )
	    {		
		_pGroupSpace->initGroupSpace(groupKey, aggList, _pGTM->getDBMng()->getSortAreaSize(_tabSetId));
		isInit = true;
	    }

	    _pGroupSpace->insertTuple(groupKey, dataTuple);
	    _pGTM->setAllocatedSortArea(_pGroupSpace->numAllocated());
	}

	_groupingDone = true;

	if ( isInit == false )
	    return false;

	if ( _pGroupCursor )
	    delete _pGroupCursor;
	
	_pGroupCursor = _pGroupSpace->getCursor();
	
	jfl = _pGroupSpace->getSchema();

	bool moreTuple = _pGroupCursor->getFirst(jfl); 

	if ( _pHaving )
	{
	    while ( moreTuple )
	    {		

		_pHaving->getExpr()->setFieldListArray(&jfl, 1);
		_pHaving->getAggExpr()->setFieldListArray(&jfl, 1);

		setAggregationValue(_pHaving->getAggExpr(), jfl);
		setAggregationValue(_pHaving->getExpr(), jfl);
		
		if ( matchFieldValue(_pHaving->getAggExpr()->evalFieldValue(),
				     _pHaving->getExpr()->evalFieldValue(), 
				 _pHaving->getComparison()))
		{
		    return true;
		}
		else
		{
		    moreTuple = _pGroupCursor->getNext(jfl);
		}
	    }
	}

	return moreTuple;
	
    }
}

bool CegoSelect::nextJoinTuple(ListT<CegoField>& jfl, ListT<CegoField>& ofl)
{    
    
    if ( _pGTM->isAborted() )
    {
	_pGTM->proceed();
	throw Exception(EXLOC, "Query aborted");
    }

    // _pLogger->log(_modId, Logger::DEBUG, Chain("Next Join tuple ..."));

    ofl.Empty();

    while ( true )
    {

	bool joinComplete=false;
	while ( _joinLevel < _joinList.Size()  && ! joinComplete)
	{
 
	    bool moreTuple=false;
    
	    if ( _firstTuple[_joinLevel] ) 
	    {
		if ( _pTC[_joinLevel] == 0 )
		{

#ifdef CGDEBUG
		    _pLogger->log(_modId, Logger::DEBUG, Chain("Creating cursor for ") 
		    		  + _joinList[_joinLevel]->getTabName() + Chain(" on join level ") + Chain(_joinLevel));

#endif
		    _pTC[_joinLevel] = 
			new CegoDistCursor(_pGTM,_joinList[_joinLevel]);

		    _pTC[_joinLevel]->checkType();		    

		}
		else
		{
		    // _pLogger->log(_modId, Logger::DEBUG, Chain("Resetting cursor for ") 
		    // 	  +  _joinList[_joinLevel]->getTabName());
		    _pTC[_joinLevel]->reset();
		    
		}
		if ( _attrCondFlag[_joinLevel] == true )
		{
		    // _pLogger->log(_modId, Logger::DEBUG, Chain("Setting attrcond =  ") + _attrCond[_joinLevel].toChain());
		    
		    bool doSetup = true;

		    if ( _attrCond[_joinLevel].setup(_joinBuf, 0, _joinSize) == false )
		    {
			// _pLogger->log(_modId, Logger::DEBUG, Chain("Native attr cond set up failed"));
			if ( _pParentJoinBuf )
			{
			    // _pLogger->log(_modId, Logger::DEBUG, Chain("Setting up with parent join buf"));
			    if ( _attrCond[_joinLevel].setup(_pParentJoinBuf, 0, _parentJoinBufSize) == false )
			    {				    
				// _pLogger->log(_modId, Logger::DEBUG, Chain("Parent attr cond set up failed"));
				doSetup = false;
			    }
			}
			else
			{
			    doSetup = false;
			}				
		    }

		    if ( doSetup )
		    {

#ifdef CGDEBUG	    
			_pLogger->log(_modId, Logger::DEBUG, Chain("Setting attrcond =  ") + _attrCond[_joinLevel].toChain());
#endif

			_pTC[_joinLevel]->distSetup(_attrCond[_joinLevel]);    
		    }
		    else
		    {			    
			_attrCondFlag[_joinLevel]=false;
			if ( _attrPred[_joinLevel] )
			{
			    _attrPred[_joinLevel]->setChecked(false);
			}
			_pTC[_joinLevel]->distSetup();
		    }
		}
		else
		{
		    _pTC[_joinLevel]->distSetup();
		}

		/*
		
		cout << "NextTuple : Size=" << _joinSize << " NumCO= " <<  _joinList[_joinLevel]->getSubCOList().Size() << endl;
		for ( int i=_joinSize; i<_joinList[_joinLevel]->getSubCOList().Size(); i++)
		{
		    cout << "SchemaSize=" << _joinBuf[i].Size() << endl;
		}
		*/
		

		moreTuple = _pTC[_joinLevel]->nextTuple(_joinBuf, _joinSize, _joinList[_joinLevel]->getSubCOList().Size());
		
	    }
	    else
	    {
		
		/*
		cout << "NextTuple : Size=" << _joinSize << " NumCO= " <<  _joinList[_joinLevel]->getSubCOList().Size() << endl;
		for ( int i=_joinSize; i<_joinList[_joinLevel]->getSubCOList().Size(); i++)
		{
		    cout << "SchemaSize=" << _joinBuf[i].Size() << endl;
		}
		*/

		moreTuple = _pTC[_joinLevel]->nextTuple(_joinBuf, _joinSize, _joinList[_joinLevel]->getSubCOList().Size());
	    }


	    bool setFinished = false;

	    if ( moreTuple)
	    {
		_firstTuple[_joinLevel]=false;
		
		if ( _joinLevel < _joinList.Size() - 1 )
		{
		    _joinSize += _joinList[_joinLevel]->getSubCOList().Size();
		    _joinLevel++;
		}
		else
		    joinComplete=true;
	    }
	    else
	    {		
		setFinished = true;
	    }
	    

	    if ( setFinished )
	    {

		_firstTuple[_joinLevel]=true;

		if ( _joinLevel > 0 )
		{
		    _joinSize -= _joinList[_joinLevel]->getSubCOList().Size();
		    _joinLevel--;
		}
		else
		{
		    int i=0;
		    while ( i < TABMNG_MAXJOINLEVEL )
		    {			
			if ( _pTC[i] )
			    _pTC[i]->reset();
			i++;
		    }
		    return false;
		}
	    }
	}


	bool checkPred = true;
	CegoPredDesc **pPred = _conjunctionList.First();

	while ( pPred && checkPred )
	{

	    if ( ! (*pPred)->isChecked() )
	    {
#ifdef CGDEBUG
		_pLogger->log(_modId, Logger::DEBUG, Chain("Evaluating predicate ") + (*pPred)->toChain());
#endif
		CegoQueryHelper queryHelper;
				
		// (*pPred)->clearAttrCache();

		checkPred = queryHelper.evalPredicate(_pParentJoinBuf,
						      0,
						      _parentJoinBufSize, 
						      _joinBuf,
						      0,
						      _joinSize + _joinList[_joinLevel]->getSubCOList().Size(),
						      *pPred, _pBlock);
						      
		// _pLogger->log(_modId, Logger::DEBUG, Chain("Evaluating predicate done"));		

	    }

	    pPred = _conjunctionList.Next();
	}


	if ( checkPred )
	{


	    // _pLogger->log(_modId, Logger::DEBUG, Chain("Join buf matches"));
	    
	    bool isAgg;
	    if ( _selectMode == AGGREGATION || _selectMode == GROUPING )
		isAgg=true;
	    else
		isAgg=false;

	    CegoQueryHelper qh;

	    jfl.Empty();
	    qh.evalSelection(_exprList, _joinBuf, _joinSize + _joinList[_joinLevel]->getSubCOList().Size(), isAgg, jfl);

	    // _pLogger->log(_modId, Logger::DEBUG, Chain("Selection evaluated"));

	    if ( _pOrderList )
	    {
		CegoExpr **pExpr = _pOrderList->First();
		while ( pExpr )
		{
		    ListT<CegoAttrDesc*> attrRefList = (*pExpr)->getAttrRefList();
		    
		    CegoAttrDesc** pAttrRef = attrRefList.First();
		    
		    while ( pAttrRef )
		    {
			int i=0;
			bool notFound=true;
			while ( i< _joinSize + _joinList[_joinLevel]->getSubCOList().Size()
				&& notFound )
			{
			    if ( CegoField* pF = (&_joinBuf[i])->Find(CegoField((*pAttrRef)->getTableName(), (*pAttrRef)->getAttrName())) )
			    {
				ofl.Insert(*pF);
				notFound=false;
			    }
			    i++;
			}
			if ( notFound )
			{
			    Chain msg = Chain("Unknown order attribute ") + (*pAttrRef)->getTableName() + Chain(".") + (*pAttrRef)->getAttrName();
			    throw Exception(EXLOC, msg);
			}			
			pAttrRef = attrRefList.Next();
		    }
		    
		    pExpr = _pOrderList->Next();
		}
	    }
	    return true;
	}
    }
}

CegoPredDesc* CegoSelect::getPredicate()
{
    return _pPred;
}

void CegoSelect::getSchema(ListT<CegoField>& schema)
{

    if ( _exprList.isEmpty() )
    {
	schema = _joinFields;
    }
    else
    {
	CegoExpr** pExpr = _exprList.First();
	while ( pExpr )
	{
	    CegoAttrDesc* pAttrDesc = (*pExpr)->checkAttr();
	    if ( pAttrDesc )
	    {
		if ( pAttrDesc->getAttrName() == Chain(SELECTION_WILDCARD))
		{
		    bool refFound=false;
		    CegoField *pF = _joinFields.First();
		    while ( pF )
		    {
			if ( (Chain)pF->getTableName() ==  (Chain)pAttrDesc->getTableName()
			     || (Chain)pF->getTableAlias() ==  (Chain)pAttrDesc->getTableName() )
			{
			    refFound=true;

			    schema.Insert(*pF);
			}
			pF = _joinFields.Next();
		    }
		    if ( refFound == false )
		    {
			Chain msg = Chain("Unknown table reference ") + pAttrDesc->getTableName();
			throw Exception(EXLOC, msg);		    
		    }
		}
		else
		{
		    (*pExpr)->setFieldListArray( &_joinFields, 1 );
		    CegoField f = (*pExpr)->evalField();
		    schema.Insert(f);	       
		}
	    }
	    else
	    {
		(*pExpr)->setFieldListArray( &_joinFields, 1 );
		CegoField f = (*pExpr)->evalField();
		schema.Insert(f);		
	    }
	    pExpr = _exprList.Next();
	}
    }

    return;
}

void CegoSelect::createConjunctionList(CegoPredDesc* pPred)
{
    if (pPred)
    {
	CegoCondDesc* pC = pPred->getCondition();	
	if (pC)
	{
	    if (pC->getCondType() == CegoCondDesc::AND)
	    {
		createConjunctionList(pC->Left());
		createConjunctionList(pC->Right());
	    }
	    else
	    {
		_conjunctionList.Insert(pPred);
	    }
	}
	else
	{
	    _conjunctionList.Insert(pPred);
	}
    }
}

void CegoSelect::consolidateConjunctionList()
{

    bool finished = false;
    
    while ( finished == false )
    {
	SetT<Chain> tableRefSetA;
	SetT<Chain> tableRefSetB;
	
	bool predFound = false;
	CegoPredDesc **pPredA = _conjunctionList.First();
	while ( pPredA && predFound == false)
	{
	    if ( (*pPredA)->isChecked() == false && (*pPredA)->hasOrCond() == false )
		predFound = true;
	    else
		pPredA = _conjunctionList.Next();
	}
	
	if ( pPredA )
	{      
	    tableRefSetA = (*pPredA)->getTableRefSet();
	    (*pPredA)->setChecked(true);
	}
	else
	{
	    finished = true;
	}
	
	if ( finished == false )
	{
	    bool isMerged=false;
	    CegoPredDesc **pPredB = _conjunctionList.Next();
	    while ( pPredB && isMerged == false )
	    {
		if ( (*pPredB)->hasOrCond() )
		{
		    pPredB = _conjunctionList.Next();
		}
		else
		{
		    tableRefSetB = (*pPredB)->getTableRefSet();
		    
		    if ( tableRefSetA == tableRefSetB )
		    {
			CegoPredDesc *pA = *pPredA;
			CegoPredDesc *pB = *pPredB;
			
			// cout << "Pred A =  " << (*pPredA)->toChain()  << endl;	    
			// cout << "Pred B =  " << (*pPredB)->toChain()  << endl;	    
			
			_conjunctionList.Remove(*pPredA);
			_conjunctionList.Remove(*pPredB);
			
			CegoCondDesc* pCond = new CegoCondDesc(CegoCondDesc::AND);
			pCond->setLeft(pA);
			pCond->setRight(pB);
			
			_conjunctionList.Insert(new CegoPredDesc(pCond));
			isMerged = true;
		    }
		    if ( isMerged == false )
			pPredB = _conjunctionList.Next();
		}
	    }
	}
    }

    CegoPredDesc **pPred = _conjunctionList.First();
    while ( pPred )
    {
	(*pPred)->setCheckedRec(false);
	pPred = _conjunctionList.Next();
    }
    
}

//
// the buildJoinObjects method provides an appropriate order of the required join tables
// for the join execution. In this sense, first the table are joined, where predicates have
// been defined. In this sense, inner and outer joins are treated first 
//

void CegoSelect::buildJoinTables()
{
    // growStep is the number of tables to join with the next join step
    // we start with growStep 1 
    int growStep=1;
    
    while ( _joinList.Size() != _coList.Size() && growStep <= _coList.Size() )
    {
	bool isGrowing = true;
	while ( isGrowing  )
	{
	    isGrowing = false;
	    CegoPredDesc **pPred = _conjunctionList.First();
	    while ( pPred )
	    {
		// cout << "Analysing predicate .." << endl;
		ListT<CegoContentObject*> newObjectList;

		getPredObjectList(*pPred, newObjectList);

		CegoContentObject** pOE = _joinList.First();
		while ( pOE )
		{    		    
		    CegoContentObject **pNCO = newObjectList.First();
		    while ( pNCO )
		    {
			if ( (**pNCO) == (**pOE) )
			{
			    newObjectList.Remove(*pNCO);
			    pNCO = newObjectList.First();
			}
			else
			{
			    pNCO = newObjectList.Next();
			}
		    }
		    pOE = _joinList.Next();
		}

		if ( newObjectList.Size() == growStep )
		{	
		    _joinList += newObjectList;
		    isGrowing = true;
		}
		pPred = _conjunctionList.Next();
	    }	    
	}
	growStep++;
    }

    if ( _joinList.Size() != _coList.Size() )
    {

	CegoContentObject** pCO = _coList.First();
	
	while (pCO)
	{	
	    	    
	    bool notFound=true;
	    CegoContentObject **pJCO = _joinList.First();
	    while ( pJCO )
	    {
		if ( (Chain)(*pJCO)->getName() == (Chain)(*pCO)->getName())
		    notFound=false;
		pJCO = _joinList.Next();
	    }
	    
	    if ( notFound )
	    {
		_joinList.Insert(*pCO);
	    }
	    
	    pCO = _coList.Next();
	    
	}
    }
        
    CegoContentObject** pJCO = _joinList.First();
    while ( pJCO )
    {
	if ( (*pJCO)->getType() != CegoObject::JOIN )
	{
	    CegoField *pF =  (*pJCO)->getSchema().First();
	    while (pF)
	    {
		pF->setTableName((*pJCO)->getTabName());
		pF->setTableAlias((*pJCO)->getName());
		pF = (*pJCO)->getSchema().Next();
	    }
	}

	pJCO = _joinList.Next();
    }
}

void CegoSelect::buildJoinConditions()
{
    CegoQueryHelper queryHelper;

    if ( _pPred )
	_pPred->setCheckedRec(false);

    CegoPredDesc **pP = _conjunctionList.First();
    while ( pP )
    {
	(*pP)->setCheckedRec(false);
	pP = _conjunctionList.Next();
    }

    int i = 0;

    while ( i < TABMNG_MAXJOINLEVEL )
    {
	_attrCondFlag[i]=false;
	i++;
    }

    i = 0;

    ListT<CegoField> availJoinFields;

    if ( _pParentJoinBuf )
    {       
	for ( int j=0; j<_parentJoinBufSize; j++ )	    
	    availJoinFields += _pParentJoinBuf[j];
    }

    // _pLogger->log(_modId, Logger::DEBUG, Chain("Checking view condition ..."));

    if ( i >= TABMNG_MAXJOINLEVEL )
	throw Exception(EXLOC, "Join levels exceeded");

    if ( ! _conjunctionList.isEmpty() )
    {

	// _pLogger->log(_modId, Logger::DEBUG, Chain("Checking conjunctionlist ..."));
	while ( i < _joinList.Size() )
	{
	    
	    _attrCondFlag[i] = false;
	    
	    CegoPredDesc **pPred = _conjunctionList.First();
	
	    // _pLogger->log(_modId, Logger::DEBUG, Chain("Checking next predicate ..."));

	    bool notFound = true;
	    while ( pPred && notFound )
	    {
		// _pLogger->log(_modId, Logger::DEBUG, Chain("Checking predicate ") + (*pPred)->toChain());
		if ( (*pPred)->isChecked() == false )
		{
		
		    CegoAttrCond ac;
		    			   		    
#ifdef CGDEBUG
		    _pLogger->log(_modId, Logger::DEBUG, Chain("Getting attribute cond for ") + (*pPred)->toChain());
#endif
		    CegoQueryHelper::AttrCondMatch m = queryHelper.checkAttrCond(ac, *pPred, _joinList[i]->getSchema(), &availJoinFields, 1, _pBlock);		    		    
		   
		    if ( m != CegoQueryHelper::INAPP )
		    {
			// _pLogger->log(_modId, Logger::DEBUG, Chain("Detecting valid attr cond ") + ac.toChain());
						
			// before we can use the attrCond as index cursor condition, we have to 
			// check out if the object is a view or if an appropriate index exists

			/*
			CegoAttrCond::IndexMatch idxMatch = CegoAttrCond::INAPP;

			if ( _joinList[i]->getType() == CegoObject::JOIN )
			{
			    // useAttrCond = true;
			    // predChecked = true;
			}
			else if (  _pGTM->distObjectExists( _joinList[i]->getTabName(), 
							    _joinList[i]->getTabSetId(),
							    CegoObject::VIEW ) )
			{
			    // useAttrCond = true;
			    // predChecked = true;
			}
			else 
			{
			    
			    idxMatch = _pGTM->distIndexExists( _joinList[i]->getTabSetId(),
							       _joinList[i]->getTabName(), 
							       ac );
			    
			    if ( idxMatch == CegoAttrCond::INAPP )
			    {
				useAttrCond = true;
				predChecked = true;
			    }
			    else if ( idxMatch == CegoAttrCond::PART )
			    {
				useAttrCond = true;
				predChecked = true;
			    }
			    else if ( idxMatch == CegoAttrCond::FULL )
			    {
				useAttrCond = true;
				predChecked = true;
			    }
			    
			}
			*/


			bool predChecked = false;
			
			if ( m == CegoQueryHelper::COMPLETE )
			    predChecked = true;

#ifdef CGDEBUG
			_pLogger->log(_modId, Logger::DEBUG, Chain("Detecting valid attr cond [ ") + ac.toChain() + Chain(" ]"));
#endif 			

			notFound = false;		
			_attrCond[i] = ac;
			_attrCondFlag[i] = true;
						
			(*pPred)->setChecked(predChecked);
			_attrPred[i] = *pPred;
			
		    }
		    else
		    {
			pPred = _conjunctionList.Next();
		    }		    
		}
		else
		{
		    pPred = _conjunctionList.Next();
		}		
	    }

	    availJoinFields += _joinList[i]->getSchema();
	    i++;

	    if ( i >= TABMNG_MAXJOINLEVEL )
		throw Exception(EXLOC, "Join levels exceeded");

	}
    }
}

void CegoSelect::buildJoinRefs()
{
     
    // provide all selected fields in _joinFields

    int i=0;
    CegoContentObject** pCO = _joinList.First();
    
    while ( pCO )
    {       	
	// check for all subCO
	CegoContentObject **pSubCO = (*pCO)->getSubCOList().First();
	while ( pSubCO )
	{
	    
	    if ( (*pSubCO)->getType() != CegoObject::JOIN )
	    {
		CegoField *pF =  (*pSubCO)->getSchema().First();
		while (pF)
		{
		    pF->setTableName((*pSubCO)->getTabName());
		    pF->setTableAlias((*pSubCO)->getName());
		    pF = (*pSubCO)->getSchema().Next();
		}
	    }
	    	    	    
	    ListT<CegoField> outSchema;

	    // in case of select * get all available fields
	    if ( _exprList.isEmpty() )
	    {
		filterRefs( (*pSubCO)->getSchema(), outSchema );
		outSchema = (*pSubCO)->getSchema();
	    }
	    else
	    {
		filterRefs( (*pSubCO)->getSchema(), outSchema );
		(*pSubCO)->setSchema(outSchema);
	    }

	    // sort outSchema
	    
	    _joinBuf[i].Empty();
	    CegoField *pF = outSchema.First();
	    int maxId=0;
	    while ( pF )
	    {
		if ( pF->getId() > maxId )
		    maxId = pF->getId();
		pF = outSchema.Next();
	    }
	    for ( int id=0; id<=maxId; id++ )
	    {
		CegoField *pF = outSchema.First();
		while ( pF )
		{
		    if ( pF->getId() == id )
		    {
			_joinBuf[i].Insert(*pF);
			pF = 0;
		    }
		    else
		    {
			pF = outSchema.Next();
		    }
		}
	    }
	    
	    
	    // _joinBuf[i] = outSchema;
	    i++;
	    
	    _joinFields += (*pSubCO)->getSchema();
	    
	    pSubCO = (*pCO)->getSubCOList().Next();
	}


	pCO = _joinList.Next();
    }
}

void CegoSelect::filterRefs(ListT<CegoField>& inSchema, ListT<CegoField>& outSchema)
{
        
    if ( _exprList.isEmpty() )
    {
	outSchema = inSchema;
    }
    else
    {
	CegoExpr** pExpr = _exprList.First();
	while (pExpr)
	{
	    filterExprRef(*pExpr, inSchema, outSchema);
	    pExpr = _exprList.Next();
	}
        
	if ( _pGroupList == 0 && _selectMode == AGGREGATION )
	{
	    pExpr = _exprList.First();
	    while (pExpr)
	    {
		if (  (*pExpr)->getAggregationList().Size() == 0 )
		{
		    Chain msg = Chain("Invalid expression ") + (*pExpr)->toChain() + Chain(" for aggregation");
		    throw Exception(EXLOC, msg);
		}		
		pExpr = _exprList.Next();
	    }
	}
    }
    
    ListT<CegoField> tmpSchema[TABMNG_MAXTMPSCHEMA];

    int tmpidx=0;

    if (_pPred)
    {
	filterPredRef(_pPred, inSchema, tmpSchema[tmpidx]);
	tmpidx++;
    }

    CegoPredDesc** pJoinPred = _joinPredList.First();
    while ( pJoinPred )
    {
	filterPredRef(*pJoinPred, inSchema, tmpSchema[tmpidx]);
	tmpidx++;
	pJoinPred = _joinPredList.Next();
    }
        
    if (_pGroupList)
    {
	CegoAttrDesc** pAD = _pGroupList->First();
	while ( pAD )
	{
	    filterAttrRef(*pAD, inSchema, tmpSchema[tmpidx]);
	    pAD = _pGroupList->Next();
	}
	if ( _pHaving )
	{
	    filterExprRef(_pHaving->getAggExpr(), inSchema, tmpSchema[tmpidx]);
	    filterExprRef(_pHaving->getExpr(), inSchema, tmpSchema[tmpidx]);
	}
	tmpidx++;
    }

    if (_pNativeOrderList)
    {
	CegoExpr** pExpr = _pNativeOrderList->First();
	while ( pExpr )
	{	   
	    ListT<CegoAttrDesc*> attrRefList = (*pExpr)->getAttrRefList();
		    
	    CegoAttrDesc** pAttrRef = attrRefList.First();
	    
	    while ( pAttrRef )
	    {
		filterAttrRef(*pAttrRef, inSchema, tmpSchema[tmpidx]);
		pAttrRef = attrRefList.Next();
	    }
	    pExpr = _pNativeOrderList->Next();
	}
	tmpidx++;
    }


    // merge tmpSchemas to outSchema

    for ( int i=0; i < tmpidx; i++)
    {
	CegoField *pF = tmpSchema[i].First();
	while( pF )
	{
	    if ( outSchema.Find(*pF) == 0 )
		outSchema.Insert(*pF);
	    pF = tmpSchema[i].Next();
	}
    }
    
}

void CegoSelect::filterFacRef(CegoFactor *pFac, ListT<CegoField>& inSchema, ListT<CegoField>& outSchema)
{
    if (pFac->getType() == CegoFactor::EXPR)
    {
	filterExprRef(pFac->getExpr(), inSchema, outSchema);
    }
    else if ( pFac->getType() == CegoFactor::ATTR)
    {
	filterAttrRef(pFac->getAttr(), inSchema, outSchema);
    }
    else if ( pFac->getType() == CegoFactor::FUNCTION )
    {
	CegoFunction* pFunc = pFac->getFunction();

	CegoExpr **pFuncArg = pFunc->getExprList().First();
	while ( pFuncArg )
	{
	    filterExprRef(*pFuncArg, inSchema, outSchema);
	    pFuncArg = pFunc->getExprList().Next();
	}
    }
    else if (  pFac->getType() == CegoFactor::AGGREGATION )
    {
	_selectMode = AGGREGATION;

	if ( pFac->getAggregation()->getExpr() )
	    filterExprRef(pFac->getAggregation()->getExpr(), inSchema, outSchema);
	
	pFac->getAggregation()->setAggregationId(_nextAid);
	_nextAid++;
    }
    else if (  pFac->getType() == CegoFactor::QUERY )
    {
	pFac->getSelect()->prepare();
	ListT<CegoAttrDesc*> attrRefList = pFac->getAttrRefList();
	CegoAttrDesc** pAttr = attrRefList.First();
	while ( pAttr )
	{
	    filterAttrRef( *pAttr, inSchema, outSchema );
	    pAttr = attrRefList.Next();
	}
    }
    else if (  pFac->getType() == CegoFactor::CASECOND )
    {
	CegoCaseCond *pCaseCond = pFac->getCaseCond();
 
	ListT<CegoField> outSchema2;
	CegoPredDesc **pPred = pCaseCond->getPredList().First();
	while ( pPred )
	{
	    filterPredRef(*pPred, inSchema, outSchema2);
	    pPred = pCaseCond->getPredList().Next();
	}
	ListT<CegoField> outSchema3;
	CegoExpr **pExpr = pCaseCond->getExprList().First();
	while ( pExpr )
	{
	    filterExprRef(*pExpr, inSchema, outSchema3);
	    pExpr = pCaseCond->getExprList().Next();
	}
	ListT<CegoField> outSchema4;
	if ( pCaseCond->getElseExpr() )
	    filterExprRef(pCaseCond->getElseExpr(), inSchema, outSchema4);

	// merge outSchemas
	CegoField *pF = outSchema2.First();
	while( pF )
	{
	    if ( outSchema.Find(*pF) == 0 )
		outSchema.Insert(*pF);
	    pF = outSchema2.Next();
	}
	pF = outSchema3.First();
	while( pF )
	{
	    if ( outSchema.Find(*pF) == 0 )
		outSchema.Insert(*pF);
	    pF = outSchema3.Next();
	}
	pF = outSchema4.First();
	while( pF )
	{
	    if ( outSchema.Find(*pF) == 0 )
		outSchema.Insert(*pF);
	    pF = outSchema4.Next();
	}
    }
}

void CegoSelect::filterExprRef(CegoExpr *pExpr, ListT<CegoField>& inSchema, ListT<CegoField>& outSchema)
{
    switch ( pExpr->getType() )
    {
    case CegoExpr::ADD:
    case CegoExpr::SUB:
    case CegoExpr::CONCAT:
    {
	filterExprRef(pExpr->getExpr(), inSchema, outSchema);	
	filterTermRef(pExpr->getTerm(), inSchema, outSchema);
	break;
    }
    case CegoExpr::TERM:
    {
	filterTermRef(pExpr->getTerm(), inSchema, outSchema);
	break;
    }
    }
}

void CegoSelect::filterTermRef(CegoTerm *pTerm, ListT<CegoField>& inSchema, ListT<CegoField>& outSchema)
{   

    switch ( pTerm->getType() )
    {
    case CegoTerm::MUL:
    case CegoTerm::DIV:
    {
	filterTermRef(pTerm->getTerm(), inSchema, outSchema);	
	filterFacRef(pTerm->getFactor(), inSchema, outSchema);
	break;
    }
    case CegoTerm::FACTOR:
    {	
	filterFacRef(pTerm->getFactor(), inSchema, outSchema);
	break;
    }      
    }
}

void CegoSelect::filterAttrRef(CegoAttrDesc* pAttrDesc, ListT<CegoField>& inSchema, ListT<CegoField>& outSchema)
{
    CegoField* pF = inSchema.First();
    while ( pF )
    {
	if ( ( (Chain)pAttrDesc->getAttrName() == (Chain)pF->getAttrName() 
	       || (Chain)pAttrDesc->getAttrName() == Chain(SELECTION_WILDCARD))
	     && (Chain)pAttrDesc->getTableName() == (Chain)pF->getTableAlias())
	{
	    if ( outSchema.Find(*pF) == 0 )
		outSchema.Insert(*pF);
	    // cout << "Setting " << pAttrDesc->toChain() << " valid " << (long)pAttrDesc << endl;
	    pAttrDesc->setValid(true);
	}
	
	pF = inSchema.Next();
    }
}

void CegoSelect::filterPredRef(CegoPredDesc *pP, ListT<CegoField>& inSchema, ListT<CegoField>& outSchema)
{
    
    if ( pP->getMode() == CegoPredDesc::CONDITION )
    {
	filterCondRef(pP->getCondition(), inSchema, outSchema);
    }
    else if ( pP->getMode() == CegoPredDesc::NOTPRED )
    {
	filterPredRef(pP->getNotPred(), inSchema, outSchema);
    }
    else
    {

	if ( pP->getMode() == CegoPredDesc::EXPRCOMP 
	     || pP->getMode() == CegoPredDesc::ISLIKE
	     || pP->getMode() == CegoPredDesc::ISNOTLIKE
	     || pP->getMode() == CegoPredDesc::INSUB
	     || pP->getMode() == CegoPredDesc::NOTINSUB
	     || pP->getMode() == CegoPredDesc::NULLCOMP
	     || pP->getMode() == CegoPredDesc::NOTNULLCOMP
	     || pP->getMode() == CegoPredDesc::BETWEEN)
	{

	    filterExprRef(pP->getExpr1(), inSchema, outSchema);

	    if ( pP->getMode() == CegoPredDesc::EXPRCOMP 
		 || pP->getMode() == CegoPredDesc::BETWEEN )
	    {
		filterExprRef(pP->getExpr2(), inSchema, outSchema);
	    }
	    if ( pP->getMode() == CegoPredDesc::BETWEEN )
	    {
		filterExprRef(pP->getExpr3(), inSchema, outSchema);
	    }	   	    
	}
	
	if ( pP->getMode() == CegoPredDesc::EXISTSCOMP
	     || pP->getMode() == CegoPredDesc::INSUB
	     || pP->getMode() == CegoPredDesc::NOTINSUB)
	{

	    ListT<CegoSelect*> queryList;
	    pP->getSelectQueryList(queryList);

	    CegoSelect **pSelect = queryList.First();
	    while ( pSelect )
	    {
		ListT<CegoAttrDesc*> attrRefList = (*pSelect)->getAttrRefList();
		CegoAttrDesc **pAD = attrRefList.First();
		while ( pAD )
		{
		    filterAttrRef((*pAD), inSchema, outSchema);
		    pAD = attrRefList.Next();
		}
		
		/*
		cout << "YYY " << (*pSelect)->toChain()  << endl;
		if ( (*pSelect)->getPredicate() )
		{
		    cout << "FILTER PRED REF" << endl;
		    filterPredRef((*pSelect)->getPredicate(), inSchema, outSchema);
		}
		*/
		pSelect = queryList.Next();
	    }
	}
    }
}

void CegoSelect::filterCondRef(CegoCondDesc* pC, ListT<CegoField>& inSchema, ListT<CegoField>& outSchema)
{
    if (pC->Left())
    {
	filterPredRef(pC->Left(), inSchema, outSchema);
    }
    if (pC->Right())
    {
	filterPredRef(pC->Right(), inSchema, outSchema);
    }
}

void CegoSelect::getPredObjectList(CegoPredDesc *pPred, ListT<CegoContentObject*>& objectList)
{
    if ( _pGTM == 0 )
	throw Exception(EXLOC, "No tablemanager set");

    if ( pPred->getCondition() )
    {
	getCondObjectList(pPred->getCondition(), objectList);
    }
    else
    {	
	if ( pPred->getExpr1() )
	{
	    ListT<CegoAttrDesc*> attrRefList = pPred->getExpr1()->getAttrRefList();

	    if ( pPred->getExpr2() )
	    {
		attrRefList += pPred->getExpr2()->getAttrRefList();
	    }

	    CegoContentObject** pCO = _coList.First();	
	    while (pCO)
	    {	

		// check for all subCO
		CegoContentObject **pSubCO = (*pCO)->getSubCOList().First();
		while ( pSubCO )
		{
				
		    CegoAttrDesc **pAttr = attrRefList.First();
		    
		    while ( pAttr )
		    {
			
			if ( (Chain)(*pAttr)->getTableName() == (Chain)(*pSubCO)->getTabName() 
			     || (Chain)(*pAttr)->getTableName() == (Chain)(*pSubCO)->getName())
			    
			{			    
			    // check if content object already in object list
			    bool notFound=true;
			    CegoContentObject **pCCO = objectList.First();
			    while ( pCCO && notFound )
			    {
				if ( (Chain)(*pCCO)->getName() == (Chain)(*pCO)->getName())
				    notFound=false;
				else
				    pCCO = objectList.Next();
			    }
			    if ( notFound )
			    {
				objectList.Insert(*pCO);
			    }	      
			}
			pAttr = attrRefList.Next();	    
		    }

		    pSubCO = (*pCO)->getSubCOList().Next();
		    
		}
		pCO = _coList.Next();	    
	    }
	}
    }
}

void CegoSelect::getCondObjectList(CegoCondDesc* pC, ListT<CegoContentObject*>& objectList)
{
    if (pC->Left())
    {
	getPredObjectList(pC->Left(), objectList);
    }
    if (pC->Right())
    {
	getPredObjectList(pC->Right(), objectList);
    }
}

// the evalReferences method resolves all occuring attribute references to full   
// table information for later processing. In these terms, the defined selection list
// but also all refrences in the condition clause are resolved.

int CegoSelect::evalExtTableReferences(CegoContentObject* pCO, const ListT<CegoField>& fl)
{
    int refCount = evalTableReferences(pCO, fl); 
    _extRefCount += refCount;
    return refCount;
}

int CegoSelect::evalTableReferences(CegoContentObject *pCO, const ListT<CegoField>& fl)
{

    int refCount = 0;

    CegoExpr** pExpr = _exprList.First();
    while (pExpr)
    {	
	refCount += (*pExpr)->evalReferences(pCO, fl);
	pExpr = _exprList.Next();
    }
    
    if (_pPred)
    {
	refCount += _pPred->evalReferences(pCO, fl);
    }

    CegoPredDesc **pJoinPred = _joinPredList.First();
    while (pJoinPred)
    {
	refCount += (*pJoinPred)->evalReferences(pCO, fl);
	pJoinPred = _joinPredList.Next();
    }
    
    CegoPredDesc **pP = _viewConjunctionList.First();
    while ( pP )
    {      
	refCount += (*pP)->evalReferences(pCO, fl);
	pP = _viewConjunctionList.Next();
    }
                
    if (_pGroupList)
    {
	CegoAttrDesc **pAD = _pGroupList->First();
	while ( pAD )
	{
	    refCount += (*pAD)->evalReferences(pCO, fl);
	    pAD = _pGroupList->Next();
	}
    }
    
    if (_pNativeOrderList)
    {	
	CegoExpr **pExpr = _pNativeOrderList->First();	
	while ( pExpr )
	{
	    refCount += (*pExpr)->evalReferences(pCO, fl);	
	    pExpr = _pNativeOrderList->Next();
	}	    
    }
    
    if ( _pHaving )
    {
	refCount += _pHaving->getExpr()->evalReferences(pCO, fl);
	refCount += _pHaving->getAggExpr()->evalReferences(pCO, fl);	
    }

    return refCount;
}

void CegoSelect::evalReferences()
{
    _joinPredList.Empty();
    CegoContentObject** pCO = _coList.First();
    while (pCO)
    {
	if ( (*pCO)->getType() == CegoObject::JOIN )
	{
	    ((CegoJoinObject*)(*pCO))->getPredList(_joinPredList);
	}
	pCO = _coList.Next();
    }

    pCO = _coList.First();
    while (pCO)
    {	      
	// uncompiled objects are detected here
	if ( (*pCO)->getType() == CegoObject::UNDEFINED )
	{
	    Chain msg = Chain("Invalid object ") + (*pCO)->getName();
	    throw Exception(EXLOC, msg);	    
	}

	ListT<CegoField> schema;
	schema = (*pCO)->getSchema();
	
	evalTableReferences(*pCO, schema);
	
	pCO = _coList.Next();
    }
}

// the evalSelection finalizes the selection procedure by evaluating the expressions defined in 
// the selection part. Either these are plain attributes, expressions or aggregation functions 
// the result is given in the outList parameter


void CegoSelect::evalSelection(ListT<CegoField>& ol) 
{

    if ( _exprList.isEmpty() )
    {
	
	for ( int i = 0; 
	      i < _joinSize + _joinList[_joinLevel]->getSubCOList().Size(); 
	      i++ )
	{
	    CegoField* pF = _joinBuf[i].First();
	    while ( pF ) 
	    {				
		ol.Insert(*pF);
		pF = _joinBuf[i].Next();
	    }
	}
	return;
    }


    if ( _selectMode == AGGREGATION || _selectMode == GROUPING )
    {
	CegoExpr** pExpr = _exprList.First();
	while ( pExpr )
	{
	    
	    (*pExpr)->setFieldListArray( _joinBuf, _joinSize + _joinList[_joinLevel]->getSubCOList().Size());
	    
	    ListT<CegoField> fl = (*pExpr)->getFieldList();

	    CegoField *pF = fl.First();
	    while ( pF )
	    {
		int i =0;	       
		CegoField *pJF = 0;
		while ( i < _joinSize + _joinList[_joinLevel]->getSubCOList().Size()
			&& pJF == 0 )
		{
		    CegoField *pJF = _joinBuf[i].Find(*pF);
		    if ( pJF )
		    {
			pF->setValue(pJF->getValue());			
		    }	       
		    i++;
		}
		
		pF = fl.Next();
	    }
	    
	    ol = ol + fl;

	    pExpr = _exprList.Next();
	}
    }
    else
    {

	CegoExpr** pExpr = _exprList.First();
	while ( pExpr )
	{

	    CegoAttrDesc* pAttrDesc = (*pExpr)->checkAttr();

	    if ( pAttrDesc )
	    {
		if (  pAttrDesc->getAttrName() == Chain(SELECTION_WILDCARD) )
		{

		    int i=0;
		    while ( i < _joinSize + _joinList[_joinLevel]->getSubCOList().Size() )
		    {		    
			CegoField *pF = _joinBuf[i].First();
			while ( pF )
			{
			    if ( (Chain)pF->getTableName() ==  (Chain)pAttrDesc->getTableName()
				 || (Chain)pF->getTableAlias() ==  (Chain)pAttrDesc->getTableName() )
			    {			    
				ol.Insert(*pF);
			    }
			    pF = _joinBuf[i].Next();
			}
		    }
		}
		else
		{
		    (*pExpr)->setFieldListArray( _joinBuf, _joinSize + _joinList[_joinLevel]->getSubCOList().Size());	     
		    CegoField f = (*pExpr)->evalField();
		    f.setValue ( (*pExpr)->evalFieldValue() ); 
		    
		    ol.Insert ( f );
		}
	    }
	    else
	    {
	
		(*pExpr)->setFieldListArray( _joinBuf, _joinSize + _joinList[_joinLevel]->getSubCOList().Size());	     
		CegoField f = (*pExpr)->evalField();
		f.setValue ( (*pExpr)->evalFieldValue() ); 
		
		ol.Insert ( f );
	    }
	    pExpr = _exprList.Next();
	}
    }
       
    return;
    
}


void CegoSelect::encode(char *buf)
{

    char* pBuf = (char*)buf;

    int size = 0;
    CegoExpr** pExpr = _exprList.First();
    while (pExpr)
    {
	size += (*pExpr)->getEncodingLength();
	pExpr = _exprList.Next();
    }
    
    memcpy( pBuf, &size, sizeof(int));
    pBuf = pBuf + sizeof(int);

    pExpr = _exprList.First();
    while (pExpr)
    {
	(*pExpr)->encode(pBuf);
	pBuf = pBuf + (*pExpr)->getEncodingLength();
	pExpr = _exprList.Next();
    }

    size = 0;
    CegoContentObject** pCO = _coList.First();
    while (pCO)
    {
	size += (*pCO)->getEntrySize();
	pCO = _coList.Next();
    }

    memcpy( pBuf, &size, sizeof(int));
    pBuf = pBuf + sizeof(int);

    pCO = _coList.First();
    while (pCO)
    {
	(*pCO)->encode(pBuf);
	pBuf = pBuf + (*pCO)->getEntrySize();
	pCO = _coList.Next();
    }

    size = 0;
    if (_pPred)
    {
	size = _pPred->getEncodingLength();
	memcpy( pBuf, &size, sizeof(int));
	pBuf = pBuf + sizeof(int);
	_pPred->encode(pBuf);
	pBuf = pBuf + size;
    }
    else
    {
	memcpy( pBuf, &size, sizeof(int));
	pBuf = pBuf + sizeof(int);
    }
    
    size = 0;
    if (_pGroupList)
    {

	CegoAttrDesc **pAttrDesc = _pGroupList->First();
	while ( pAttrDesc )
	{
	    size += (*pAttrDesc)->getEncodingLength();
	    pAttrDesc = _pGroupList->Next();
	}

	memcpy( pBuf, &size, sizeof(int));
	pBuf = pBuf + sizeof(int);

	pAttrDesc = _pGroupList->First();
	while ( pAttrDesc )
	{
	    (*pAttrDesc)->encode(pBuf);
	    pBuf = pBuf + (*pAttrDesc)->getEncodingLength();
	    pAttrDesc = _pGroupList->Next();
	}

	size = 0;
	if ( _pHaving )
	{
	    _pHaving->encode(pBuf);
	    pBuf = pBuf + _pHaving->getEncodingLength();
	}
	else
	{
	    memcpy( pBuf, &size, sizeof(int));
	    pBuf = pBuf + sizeof(int);
	}
    }
    else
    {
	memcpy( pBuf, &size, sizeof(int));
	pBuf = pBuf + sizeof(int);
	
    }
    size = 0;
    if ( _pOrderList )
    {
	
	CegoExpr **pExpr = _pOrderList->First();
	while ( pExpr )
	{
	    size += (*pExpr)->getEncodingLength();
	    pExpr = _pOrderList->Next();
	}
       
	memcpy( pBuf, &size, sizeof(int));
	pBuf = pBuf + sizeof(int);
	
	pExpr = _pOrderList->First();
	while (pExpr)
	{
	    (*pExpr)->encode(pBuf);
	    pBuf = pBuf + (*pExpr)->getEncodingLength();
	    pExpr = _pOrderList->Next();
	}
    }
    else
    {
	memcpy( pBuf, &size, sizeof(int));
	pBuf = pBuf + sizeof(int);
	
    }

    size = 0;
    if ( _pUnionSelect )
    {
	size = _pUnionSelect->getEncodingLength();
	memcpy( pBuf, &size, sizeof(int));
	pBuf = pBuf + sizeof(int);

	_pUnionSelect->encode(pBuf);
	pBuf = pBuf + _pUnionSelect->getEncodingLength();
    }
    else
    {
	memcpy( pBuf, &size, sizeof(int));
	pBuf = pBuf + sizeof(int);
    }

}

void CegoSelect::decode(char *buf, CegoDistManager *pGTM)
{

    char* pBuf = (char*)buf;
    
    int size;
    memcpy( &size, pBuf, sizeof(int));
    pBuf += sizeof(int);
    
    int i = 0;
    while ( i < size )
    {
	CegoExpr *pExpr = new CegoExpr(pBuf, pGTM);
	int len = pExpr->getEncodingLength();
	
	pBuf += len;
	i += len;
	
	_exprList.Insert( pExpr );
	
    }

    memcpy( &size, pBuf, sizeof(int));
    pBuf += sizeof(int);
    

    i = 0;
    while ( i < size )
    {

	CegoContentObject *pCO;

	CegoObject obj;
	int size;
	obj.decodeBase(pBuf, size);   
		
	if ( obj.getType() == CegoObject::TABLE )
	{
	    pCO = new CegoTableObject();
	}
	else if ( obj.getType() == CegoObject::VIEW )
	{
	    pCO = new CegoViewObject();
	}
	else if ( obj.getType() == CegoObject::JOIN )
	{
	    pCO = new CegoJoinObject();
	}
	pCO->decode(pBuf);	    


	int len = pCO->getEntrySize();
	
	pBuf += len;
	i += len;
	
	_coList.Insert( pCO );
	
    }

    memcpy( &size, pBuf, sizeof(int));
    pBuf += sizeof(int);
    
    if ( size > 0 )
    {
	_pPred = new CegoPredDesc(pBuf, pGTM);
	pBuf += _pPred->getEncodingLength();
    }
    else
    {
	_pPred = 0;
    }

    memcpy( &size, pBuf, sizeof(int));
    pBuf += sizeof(int);
    
    if ( size > 0 )
    {

	_pGroupList = new ListT<CegoAttrDesc*>;

	i = 0;
	while ( i < size )
	{
	    CegoAttrDesc* pAD = new CegoAttrDesc(pBuf);
	    int len = pAD->getEncodingLength();
	    
	    pBuf += len;
	    i += len;
	    
	    _pGroupList->Insert( pAD );
	    
	}
	
	memcpy( &size, pBuf, sizeof(int));
	pBuf += sizeof(int);
    
	if ( size > 0 )
	{
	    _pHaving = new CegoHavingDesc(buf, pGTM);
	    pBuf += _pHaving->getEncodingLength();
	}
	else
	{
	    _pHaving = 0;
	}
    }
    else
    {
	_pGroupList = 0;
	_pHaving = 0;
    }

    memcpy( &size, pBuf, sizeof(int));
    pBuf += sizeof(int);
    
    if ( size > 0 )
    {
	_pOrderList = new ListT<CegoExpr*>;

	int i = 0;
	while ( i < size )
	{
	    CegoExpr *pExpr = new CegoExpr(pBuf, pGTM);
	    int len = pExpr->getEncodingLength();
	    
	    pBuf += len;
	    i += len;
	    
	    _pOrderList->Insert( pExpr );
	}
    }
    else
    {
	_pOrderList = 0;
    }


    memcpy( &size, pBuf, sizeof(int));
    pBuf += sizeof(int);
    
    if ( size > 0 )
    {
	_pUnionSelect = new CegoSelect(pBuf, pGTM);
    }
    else
    {
	_pUnionSelect = 0;
    }
}

int CegoSelect::getEncodingLength() const
{
    
    int len=0;

    len += sizeof(int);
    CegoExpr** pExpr = _exprList.First();
    while (pExpr)
    {
	len += (*pExpr)->getEncodingLength();
	pExpr = _exprList.Next();
    }
    
    len += sizeof(int);
    CegoContentObject** pCO = _coList.First();
    while (pCO)
    {
	len += (*pCO)->getEntrySize();
	pCO = _coList.Next();
    }

    len += sizeof(int);

    if (_pPred)
    {
	len += _pPred->getEncodingLength();
    }

    len += sizeof(int);

    if (_pGroupList)
    {

	CegoAttrDesc **pAttrDesc = _pGroupList->First();
	while ( pAttrDesc )
	{
	    len += (*pAttrDesc)->getEncodingLength();
	    pAttrDesc = _pGroupList->Next();
	}

	len += sizeof(int);

	if ( _pHaving )
	{
	    len += _pHaving->getEncodingLength();
	}
    }

    len += sizeof(int);

    if ( _pOrderList )
    {
	
	CegoExpr **pExpr = _pOrderList->First();
	while ( pExpr )
	{
	    len += (*pExpr)->getEncodingLength();
	    pExpr = _pOrderList->Next();
	}
    }


    len += sizeof(int);

    if (_pUnionSelect)
    {
	len += _pUnionSelect->getEncodingLength();
    }

    return len;
}


void CegoSelect::setViewCond(const CegoAttrCond& attrCond)
{

    CegoPredDesc **pP = _viewConjunctionList.First();
    while ( pP )
    {      
	delete (*pP);
	pP = _viewConjunctionList.Next();
    }
    _viewConjunctionList.Empty();
    
    if ( attrCond.numComp() > 0 )
	attrCond.asConjunctionList(_exprList, _viewConjunctionList);

    cleanUp();

}


void CegoSelect::setTabSetId(int tabSetId)
{
    _tabSetId = tabSetId;
}

Chain CegoSelect::toChain(const Chain& indent) const
{
    Chain s;

    s = indent + Chain("select");

    if ( _isDistinct && _selectMode != AGGREGATION )
	s += Chain(" distinct");
    
    if ( _exprList.Size() == 0 )
    {
	s += Chain(" *\n");
    }
    else
    {
	s += Chain("\n");
	CegoExpr** pExpr = _exprList.First();
	while (pExpr)
	{
	    s += (*pExpr)->toChain(indent + Chain(" "));
	    if ( (*pExpr)->getAlias() != Chain() )
	    {
		s += Chain(" as ") + (*pExpr)->getAlias();
	    } 
	    pExpr = _exprList.Next();
	    if ( pExpr )
		s += Chain(",\n");
	}
    }

    s += Chain("\n") + indent + Chain("from\n");

    CegoContentObject** pCO = _coList.First();
    while (pCO)
    {
	s += indent + Chain(" ") + (*pCO)->toChain();
	pCO = _coList.Next();
	if ( pCO )
	    s += Chain(",\n");
    }
    

    if (_pPred)
    {
	s += Chain("\n");
	s += indent + Chain("where\n");
	s += indent + _pPred->toChain(indent + Chain(" "));
	s += Chain("\n");
    }

    if (_pGroupList)
    {
	s += Chain("\n");
	s += indent + Chain("group by\n") + indent;
	
	CegoAttrDesc **pAttrDesc = _pGroupList->First();
	while ( pAttrDesc )
	{
	    s += indent + Chain(" ") + (*pAttrDesc)->toChain();
	    pAttrDesc = _pGroupList->Next();
	    if ( pAttrDesc )
		s += ",";
	}
	
	if ( _pHaving )
	{
	    s += Chain("\n") + indent + Chain("having\n");
	    s += indent + _pHaving->toChain();
	}
    }
    if ( _pNativeOrderList )
    {
	s += Chain("\n");
	s += indent + Chain("order by\n") + indent;
	
	CegoExpr **pExpr = _pNativeOrderList->First();
	while ( pExpr )
	{
	    s += (*pExpr)->toChain(indent + Chain(" "));
	    pExpr = _pNativeOrderList->Next();
	    if ( pExpr )
		s += ",";
	}
    }

    if ( _pUnionSelect )
    {
	s += Chain("\n");
	s += indent + Chain("union all\n") + indent;
	s += _pUnionSelect->toChain(indent);
    }
    return s;
}

Element* CegoSelect::toElement() const
{
    Element *pSelectElement = new Element( XML_SELECT_ELEMENT );

    Element *pSelectionElement = new Element( XML_SELECTION_ELEMENT );
    CegoExpr** pExpr = _exprList.First();
    while (pExpr)
    {
	pSelectionElement->addContent( (*pExpr)->toElement() );	
	pExpr = _exprList.Next();
    }

    pSelectElement->addContent(pSelectionElement);
    

    Element *pCOListElement = new Element( XML_COLIST_ELEMENT );
    CegoContentObject** pCO = _coList.First();
    while (pCO)
    {
	pCOListElement->addContent( (*pCO)->getElement() );
	pCO = _coList.Next();
    }
    
    pSelectElement->addContent(pCOListElement);

    if (_pPred)
    {
	pSelectElement->addContent( _pPred->toElement() );
    }

    if (_pGroupList)
    {
	Element *pGroupingElement = new Element( XML_GROUPING_ELEMENT );

	CegoAttrDesc **pAttrDesc = _pGroupList->First();
	while ( pAttrDesc )
	{
	    pGroupingElement->addContent( (*pAttrDesc)->toElement() );
	    pAttrDesc = _pGroupList->Next();
	}
	
	if ( _pHaving )
	{
	    pGroupingElement->addContent( _pHaving->toElement() );
	}

	pSelectElement->addContent( pGroupingElement ) ;
    }
    if ( _pNativeOrderList )
    {

	Element *pOrderingElement = new Element( XML_ORDERING_ELEMENT );
	
	CegoExpr **pExpr = _pNativeOrderList->First();
	while ( pExpr )
	{
	    pOrderingElement->addContent( (*pExpr)->toElement() );
	    pExpr = _pNativeOrderList->Next();
	}
	
	pSelectElement->addContent( pOrderingElement ) ;
    }

    if ( _pUnionSelect )
    {
	pSelectElement->addContent( _pUnionSelect->toElement() );
    }

    return pSelectElement;

}

void CegoSelect::fromElement(Element *pSelectElement, CegoDistManager* pGTM)
{
        
    if ( _pPred )
	delete _pPred;

    _pPred = 0;

    CegoContentObject **pCO = _coList.First();
    while ( pCO )
    {
	delete (*pCO);
	pCO = _coList.Next();
    }
    _coList.Empty();

    CegoExpr **pExpr = _exprList.First();
    while ( pExpr )
    {
	delete (*pExpr);
	pExpr = _exprList.Next();
    }
    _exprList.Empty();
    
    if ( _pNativeOrderList )
    {
	CegoExpr **pExpr = _pNativeOrderList->First();
	while ( pExpr )
	{
	    delete (*pExpr);
	    pExpr = _pNativeOrderList->Next();
	}
	delete _pNativeOrderList;
	_pNativeOrderList = 0;
    }
   
    if ( _pGroupList )
    {

	if ( _pGroupCursor )
	    delete _pGroupCursor;

	if ( _tabSetId != 0 && _pGroupSpace )
	{	    
	    delete _pGroupSpace;
	    _pGroupSpace=0;
	}

	delete _pGroupList;
	_pGroupList = 0;
	
    }
    if ( _pHaving )
    {
	delete _pHaving;
	_pHaving = 0;
    }

    ListT<Element*> sl = pSelectElement->getChildren(XML_SELECTION_ELEMENT);
    Element **pSE = sl.First();
    if ( pSE )
    {

	ListT<Element*> el = pSelectElement->getChildren(XML_EXPR_ELEMENT);
	Element **pEE = el.First();
	while ( pEE )
	{
	    _exprList.Insert( new CegoExpr(*pEE, pGTM) );
	    pEE = el.Next();
	}
    }

    ListT<Element*> tl = pSelectElement->getChildren(XML_COLIST_ELEMENT);
    Element **pTE = tl.First();
    if ( pTE )
    {

	ListT<Element*> tdl = pSelectElement->getChildren(XML_CODESC_ELEMENT);
	Element **pTDE = tdl.First();
	while ( pTDE )
	{

	    Chain objType = (*pTDE)->getAttributeValue(XML_OBJTYPE_ATTR);

	    CegoContentObject *pCO;

	    if ( objType == Chain(XML_TABOBJ_VALUE) )
	    {
		pCO = new CegoTableObject();
	    }
	    else if ( objType == Chain(XML_VIEWOBJ_VALUE) )
	    {
		pCO = new CegoViewObject();	
	    }
	    else if ( objType == Chain(XML_JOINOBJ_VALUE) )
	    {
		pCO = new CegoJoinObject();
	    }
	    pCO->putElement(*pTDE);
	    
	    _coList.Insert( pCO);
	    pTDE = tdl.Next();
	}
    }

    ListT<Element*> pl = pSelectElement->getChildren(XML_PRED_ELEMENT);
    Element **pPE = pl.First();
    if ( pPE )
    {
	_pPred = new CegoPredDesc(*pPE, pGTM);
    }

    ListT<Element*> gl = pSelectElement->getChildren(XML_GROUPING_ELEMENT);
    Element **pGE = gl.First();
    if ( pGE )
    {

	_pGroupList = new ListT<CegoAttrDesc*>;

	ListT<Element*> adl = (*pGE)->getChildren(XML_ATTRDESC_ELEMENT);
	Element **pADE = adl.First();
	while ( pADE )
	{
	    CegoAttrDesc* pAD = new CegoAttrDesc(*pADE);
	    _pGroupList->Insert( pAD );
	    pADE = adl.Next();
	}

	ListT<Element*> hl = (*pGE)->getChildren(XML_HAVING_ELEMENT);
	Element **pHE = hl.First();
	if ( pHE )
	{
	    _pHaving = new CegoHavingDesc(*pHE, pGTM);
	}
    }

    ListT<Element*> ol = pSelectElement->getChildren(XML_ORDERING_ELEMENT);
    Element **pOE = ol.First();
    if ( pOE )
    {

	_pNativeOrderList = new ListT<CegoExpr*>;


	ListT<Element*> el = (*pOE)->getChildren(XML_EXPR_ELEMENT);
	Element **pEE = el.First();
	while ( pEE )
	{
	    _pNativeOrderList->Insert( new CegoExpr(*pEE, pGTM) );
	    pEE = el.Next();
	}
    }

    ListT<Element*> ul = pSelectElement->getChildren(XML_SELECT_ELEMENT);
    Element **pUE = ul.First();
    if ( pUE )
    {
	_pUnionSelect = new CegoSelect(*pUE, pGTM);
    }
}

ListT<CegoAttrDesc*> CegoSelect::getAttrRefList() const
{
    ListT<CegoAttrDesc*> attrList;

    CegoContentObject** pCO = _coList.First();
    while ( pCO )
    {	
	if ( (*pCO)->getType() == CegoObject::JOIN )
	{	
	    ListT<CegoPredDesc*> predList;
	    ((CegoJoinObject*)(*pCO))->getPredList(predList);
	    
	    CegoPredDesc **pPred = predList.First();
	    while (pPred)
	    {
		attrList += (*pPred)->getAttrRefList();
		pPred = predList.Next();
	    }
	}
	pCO = _coList.Next();
    }

    CegoExpr** pExpr = _exprList.First();
    while (pExpr)
    {
	attrList += (*pExpr)->getAttrRefList();	
	pExpr = _exprList.Next();
    }

    if (_pPred)
    {
	attrList += _pPred->getAttrRefList();
    }

    if (_pGroupList)
    {
    
	CegoAttrDesc **pAttrDesc = _pGroupList->First();
	while ( pAttrDesc )
	{
	    attrList.Insert(*pAttrDesc);
	    pAttrDesc = _pGroupList->Next();
	}
	
	if ( _pHaving )
	{
	    attrList += _pHaving->getAttrRefList();
	}

    }
    
    if ( _pNativeOrderList )
    {
	
	CegoExpr **pExpr = _pNativeOrderList->First();
	while ( pExpr )
	{
	    attrList += (*pExpr)->getAttrRefList();
	    pExpr = _pNativeOrderList->Next();
	}
	
    } 
    

    return attrList;
}

ListT<CegoField> CegoSelect::getFieldList() const
{

    ListT<CegoField> fl;

    ListT<CegoAttrDesc*> attrRefList = getAttrRefList();
    CegoAttrDesc **pAD = attrRefList.First();
    while ( pAD )
    {	
	fl.Insert(CegoField((*pAD)->getTableName(), (*pAD)->getAttrName()));
	pAD = attrRefList.Next();
    }
    
    return fl;
}

void CegoSelect::initAggregation()
{
    int nextAid=0;
    
    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {

	ListT<CegoAggregation*> aggList = (*pExpr)->getAggregationList();

	CegoAggregation **pAgg = aggList.First();

	while ( pAgg )
	{	    
	    if ( (*pAgg)->getType() == CegoAggregation::COUNT )
	    {
		(*pAgg)->setFieldValue( CegoFieldValue(INT_TYPE, Chain("0")));
	    }
	    else
	    {
		CegoFieldValue fv;
		(*pAgg)->setFieldValue(fv);
	    }
	    (*pAgg)->setAggregationId(nextAid);
	    nextAid++;
	    
	    pAgg = aggList.Next();
	}
	pExpr = _exprList.Next();
    }   
}

void CegoSelect::aggregateTuple(ListT<CegoField>& aggTuple)
{

    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {       
	CegoQueryHelper qh;	
	qh.aggregateTuple(aggTuple, *pExpr);
	pExpr = _exprList.Next();
    }    
}

void CegoSelect::evalAggregation(ListT<CegoField>& resultList)
{
    
    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	
	ListT<CegoAggregation*> aggList = (*pExpr)->getAggregationList();

	CegoAggregation **pAgg = aggList.First();
	
	while ( pAgg )
	{
	    
	    if ( (*pAgg)->getType() == CegoAggregation::AVG )
	    {
		CegoFieldValue avg;
		if ( _aggregationCount > 0 && (*pAgg)->getFieldValue().isNull() == false )
		{
		    CegoFieldValue fv((*pAgg)->getFieldValue().getType(), Chain(_aggregationCount));
		    avg = (CegoFieldValue)(*pAgg)->getFieldValue() / fv ; 
		}
		(*pAgg)->setFieldValue(avg);

	    }
	    
	    pAgg = aggList.Next();
	}
	
	bool notFound=true;
	CegoFieldValue fv = (*pExpr)->evalFieldValue();
	
	// is the aggregation is associated with an alias ?
	// this may happen for aggregation in views
	CegoField* pF = resultList.First();
	while ( pF && notFound )
	{
	    if ( pF->getAttrName() != Chain() && pF->getAttrName() == (*pExpr)->getAlias() )
	    {
		pF->setValue(fv);
		notFound = false;
	    }
	    pF = resultList.Next();
	}
	
	// if native aggregation, we add it to list
	if (  notFound )
	    resultList.Insert(CegoField(fv));

	pExpr = _exprList.Next();
    }
}

void CegoSelect::makeOrder()
{

    if ( _isDistinct )
    {
	if ( _pNativeOrderList == 0 )
	{
	    
	    _pOrderList = new ListT<CegoExpr*>;
	    _pOrderOptList = new ListT<CegoOrderNode::Ordering>;
	    
	    _dcount=0;
	    CegoExpr** pExpr = _exprList.First();
	    while (pExpr)
	    {
		if ( _selectMode == AGGREGATION )
		{
		    ListT<CegoAttrDesc*> attrList = (*pExpr)->getAttrRefList();
		    CegoAttrDesc **pAD = attrList.First();
		    while ( pAD )
		    {
			CegoExpr* pAggExp = new CegoExpr( 
			    new CegoTerm( 
				new CegoFactor( *pAD, true)));
			_pOrderList->Insert(pAggExp);
			_pOrderOptList->Insert(CegoOrderNode::ASC);
			
			_dcount++;
			pAD = attrList.Next();
		    }
		}
		else
		{
		    _pOrderList->Insert((*pExpr)->clone(true));
		    _pOrderOptList->Insert(CegoOrderNode::ASC);
		    _dcount++;
		}
		
		pExpr = _exprList.Next();
	    }
	}
	else
	{	    
	    
	    _pOrderList = new ListT<CegoExpr*>;
	    _pOrderOptList = new ListT<CegoOrderNode::Ordering>;	    
	    _dcount=0;
	    
	    CegoExpr** pExpr = _pNativeOrderList->First();
	    CegoOrderNode::Ordering* pOrd = _pNativeOrderOptList->First();
	    while ( pExpr && pOrd )
	    {
		_pOrderList->Insert((*pExpr)->clone(true));
		_pOrderOptList->Insert(*pOrd);
		_dcount++;
		pExpr = _pNativeOrderList->Next();
		pOrd = _pNativeOrderOptList->Next();	  
	    }	
	    
	    if ( _selectMode != AGGREGATION )
	    {
		
		pExpr = _exprList.First();
		while ( pExpr )
		{
		    CegoAttrDesc* pAttrDesc1 = (*pExpr)->checkAttr();
		    if ( pAttrDesc1 )
		    {
			bool found=false;
			CegoExpr** pOrderExpr = _pNativeOrderList->First();
			while ( pOrderExpr && found == false )
			{
			    CegoAttrDesc* pAttrDesc2 = (*pOrderExpr)->checkAttr();
			    if ( pAttrDesc2 )
			    {
				if ( pAttrDesc1->getAttrName() == pAttrDesc2->getAttrName() )
				{
				    found = true;
				}
			    }
			    pOrderExpr = _pNativeOrderList->Next();
			}
			if ( found == false )
			{
			    _pOrderList->Insert((*pExpr)->clone(true));
			    _pOrderOptList->Insert(CegoOrderNode::ASC);
			    _dcount++;		    
			}		
		    }
		    else
		    {
			_pOrderList->Insert((*pExpr)->clone(true));
			_pOrderOptList->Insert(CegoOrderNode::ASC);
			_dcount++;
		    }
		    pExpr = _exprList.Next();
		}
	    }
	}
    }
    else
    {
	if ( _pNativeOrderList )
	{
	    _pOrderList = new ListT<CegoExpr*>;
	    _pOrderOptList = new ListT<CegoOrderNode::Ordering>;
	    
	    CegoExpr** pExpr = _pNativeOrderList->First();
	    CegoOrderNode::Ordering *pOrdering = _pNativeOrderOptList->First();
	    while (pExpr && pOrdering)
	    {
		_pOrderList->Insert((*pExpr)->clone(true));
		_pOrderOptList->Insert(*pOrdering);
		pExpr = _pNativeOrderList->Next();
		pOrdering = _pNativeOrderOptList->Next();
	    }
	}
    }
    return;
}

bool CegoSelect::matchFieldValue(const CegoFieldValue& fv1, const CegoFieldValue& fv2, CegoComparison comp)
{
    if (fv1 < fv2 && ( comp == LESS_THAN || comp == LESS_EQUAL_THAN || comp == NOT_EQUAL ))
    {       
	return true;
    }
    if (fv1 > fv2 && ( comp == MORE_THAN || comp == MORE_EQUAL_THAN || comp == NOT_EQUAL ))
    {
	return true;
    }    
    if ( fv1 == fv2 && ( comp == MORE_EQUAL_THAN || comp == LESS_EQUAL_THAN || comp == EQUAL) )
    {
	return true;
    }
    return false;
}

void CegoSelect::setAggregationValue(CegoExpr *pExpr, ListT<CegoField>& jfl)
{
    ListT<CegoAggregation*> aggList = pExpr->getAggregationList();
    
    CegoAggregation **pAgg = aggList.First();
    while ( pAgg )
    {
	CegoField *pF = jfl.First();
	while ( pF )
	{
	    if ( pF->getId() == (*pAgg)->getAggregationId() )
	    {
		(*pAgg)->setFieldValue(pF->getValue());
		pF = 0;
	    }
	    else
	    {
		pF = jfl.Next();
	    }
	}
	pAgg = aggList.Next();
    }
}

int CegoSelect::getExtRefCount() const
{
    
    return _extRefCount;
}

CegoSelect* CegoSelect::clone(bool isAttrRef)
{

    ListT<CegoExpr*> exprList;
    CegoExpr **pExpr = _exprList.First();
    while ( pExpr )
    {
	exprList.Insert((*pExpr)->clone(isAttrRef));
	pExpr = _exprList.Next();
    }
    
    CegoPredDesc *pPred = 0;
    if ( _pPred )
    {
	pPred = _pPred->clone(isAttrRef);
    }

    ListT<CegoAttrDesc*> *pGroupList = 0;

    if ( _pGroupList )
    {
	pGroupList = new ListT<CegoAttrDesc*>;
	CegoAttrDesc **pAttrDesc = _pGroupList->First();
	while ( pAttrDesc )
	{
	    if ( isAttrRef )
		pGroupList->Insert(*pAttrDesc);
	    else
		pGroupList->Insert((*pAttrDesc)->clone());
	    pAttrDesc = _pGroupList->Next();
	}
    }
        
    CegoHavingDesc *pHaving = 0;
    if ( _pHaving )
    {
	pHaving = _pHaving->clone(isAttrRef);
    }

    ListT<CegoExpr*> *pOrderList = 0;
    if ( _pOrderList )
    {
	pOrderList = new ListT<CegoExpr*>;
	CegoExpr **pExpr = _pOrderList->First();
	while ( pExpr )
	{
	    pOrderList->Insert((*pExpr)->clone(isAttrRef));
	    pExpr = _pOrderList->Next();
	}
    }
    
    ListT<CegoOrderNode::Ordering>* pOrderOptList = 0;
    if ( pOrderOptList )
    {
	pOrderOptList = new ListT<CegoOrderNode::Ordering>;
	CegoOrderNode::Ordering *pOrder = _pOrderOptList->First();
	while ( pOrder )
	{
	    pOrderOptList->Insert(*pOrder);
	    pOrder = _pOrderOptList->Next();
	}
    }

    ListT<CegoContentObject*> coList;
    CegoContentObject **pCO = _coList.First();
    while ( pCO )
    {
	CegoContentObject *pCloneCO = (*pCO)->clone(isAttrRef);	
	coList.Insert(pCloneCO);	
	pCO = _coList.Next();
    }

    CegoSelect *pClone = new CegoSelect(coList,
					exprList, 
					pPred,
					pGroupList,
					pHaving,
					pOrderList,
					pOrderOptList,
					_isDistinct,
					_rowLimit,
					_pGTM);        

    if ( _pParentJoinBuf )
	pClone->setParentJoinBuf(_pParentJoinBuf, _parentJoinBufSize);
    if ( _pBlock )
	pClone->setProcBlock(_pBlock);
    if ( _pUnionSelect )
	pClone->setUnionSelect(_pUnionSelect);
    if ( _isPrepared )
	pClone->prepare();
	    
    return pClone;
}
