///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoFactor.cc
// -------------
// Cego procedure factor structure class implementation                                    
//
// Design and Implementation by Bjoern Lemke               
//                                                         
// (C)opyright 2000-2026 Bjoern Lemke 
//
// IMPLEMENTATION MODULE
//
// Class: CegoFactor
// 
// Description: Container class to describe a factor element
//
// Status: CLEAN
// 
///////////////////////////////////////////////////////////////////////////////

// INCLUDES
#include <lfcbase/Exception.h>

#include "CegoFactor.h"
#include "CegoExpr.h"
#include "CegoSelect.h"
#include "CegoCaseCond.h"
#include "CegoXMLdef.h"
#include "CegoTypeConverter.h"

#include "CegoDatabaseFormater.h"

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

CegoFactor::CegoFactor(char* buf)
{
    _pAttrDesc = 0;
    _pExpr = 0;
    _pFetch = 0;
    _pAggr = 0;
    _pFunction = 0;
    _pSelect = 0;
    _pCaseCond = 0;
    _pCond = 0;
    _flaCached = false;
    decode(buf);
}

CegoFactor::CegoFactor(const CegoFactor& pf)
{
    *this = pf;
}

CegoFactor::CegoFactor(const Chain& varName)
{
    _type = VAR;
    _varName = varName;
    _pAttrDesc = 0;
    _pExpr = 0;
    _pFetch = 0;
    _pAggr = 0;
    _pFunction = 0;
    _pSelect = 0;
    _pCaseCond = 0;
    _pCond = 0;
    _flaCached = false;
}

CegoFactor::CegoFactor(const CegoFieldValue& fv)
{
    _type = CONSTVAL;
    _fv = fv;
    _pAttrDesc = 0;
    _pExpr = 0;
    _pFetch = 0;
    _pAggr = 0;
    _pFunction = 0;
    _pSelect = 0;
    _pCaseCond = 0;
    _pCond = 0;
    _flaCached = false;
}

CegoFactor::CegoFactor(CegoExpr *pExpr)
{
    _type = EXPR;
    _pAttrDesc = 0;
    _pExpr = pExpr;
    _pFetch = 0;
    _pAggr = 0;
    _pFunction = 0;
    _pSelect = 0;
    _pCaseCond = 0;
    _pCond = 0;
    _flaCached = false;
}

CegoFactor::CegoFactor(CegoProcFetch *pFetch)
{
    _type = FETCH;
    _pAttrDesc = 0;
    _pExpr = 0;
    _pFetch = pFetch;
    _pAggr = 0;
    _pFunction = 0;
    _pSelect = 0;
    _pCaseCond = 0;
    _pCond = 0;
    _flaCached = false;
}

CegoFactor::CegoFactor(CegoAttrDesc* pAttrDesc, bool isAttrRef)
{
    _type = ATTR;
    _isAttrRef = isAttrRef;
    _pAttrDesc = pAttrDesc;
    _pFetch = 0;
    _pExpr = 0;
    _pAggr = 0;
    _pFunction = 0;
    _pSelect = 0;
    _pCaseCond = 0;
    _pCond = 0;
    _flaCached = false;
}

CegoFactor::CegoFactor(CegoFunction* pFunction)
{
    _type = FUNCTION;
    _pFunction = pFunction;
    _pAttrDesc = 0;
    _pExpr = 0;
    _pFetch = 0;
    _pAggr = 0;
    _pSelect = 0;
    _pCaseCond = 0;
    _pCond = 0;
    _flaCached = false;
}

CegoFactor::CegoFactor(CegoAggregation* pAggr)
{
    _type = AGGREGATION;
    _pAggr = pAggr;
    _pFetch = 0;
    _pAttrDesc = 0;
    _pExpr = 0;
    _pFunction = 0;
    _pSelect = 0;
    _pCaseCond = 0;
    _pCond = 0;
    _flaCached = false;
}

CegoFactor::CegoFactor(CegoSelect* pSelect)
{
    _type = QUERY;
    _pAttrDesc = 0;
    _pExpr = 0;
    _pFetch = 0;
    _pAggr = 0;
    _pFunction = 0;
    _pSelect = pSelect;
    _pCaseCond = 0;
    _pCond = 0;
    _flaCached = false;
}

CegoFactor::CegoFactor(CegoCaseCond* pCaseCond)
{
    _type = CASECOND;
    _pAttrDesc = 0;
    _pExpr = 0;
    _pFetch = 0;
    _pAggr = 0;
    _pFunction = 0;
    _pSelect = 0;
    _pCaseCond = pCaseCond;
    _pCond = 0;
    _flaCached = false;
}

CegoFactor::CegoFactor(CegoCondition* pCond)
{
    _type = CONDITION;
    _pAttrDesc = 0;
    _pExpr = 0;
    _pFetch = 0;
    _pAggr = 0;
    _pFunction = 0;
    _pSelect = 0;
    _pCaseCond = 0;
    _pCond = pCond;
    _flaCached = false;
}

CegoFactor::~CegoFactor()
{
    if ( _pAttrDesc && _isAttrRef == false)
	delete _pAttrDesc;
    if ( _pExpr )
	delete _pExpr;
    if ( _pFetch )
	delete _pFetch;
    if ( _pFunction )
	delete _pFunction;
    if ( _pAggr )
	delete _pAggr;
    if ( _pSelect )
	delete _pSelect;
    if ( _pCaseCond )
	delete _pCaseCond;
    if ( _pCond )
	delete _pCond;
}    

void CegoFactor::cleanUp()
{
    switch ( _type ) 
    {
    case ATTR:
    {
	break;
    }
    case EXPR:
    {
	_pExpr->cleanUp();
	break;
    }
    case FUNCTION:
    {
	_pFunction->cleanUp();
	break;
    }
    case AGGREGATION:
    {
	_pAggr->cleanUp();
	break;
    }
    case QUERY:
    {
	_pSelect->cleanUp();
	break;
    }
    case CASECOND:
    {
	_pCaseCond->cleanUp();
	break;
    }
    case CONDITION:
    {
	if ( _pCond )
	    _pCond->cleanUp();
	break;
    }
    case FETCH:
    {
	if ( _pFetch )
	    _pFetch->reset();
	break;
    }
    case CONSTVAL:
    case VAR:
	break;
    }
}

void CegoFactor::setQueryManager(CegoQueryManager* pTabMng)
{

    switch ( _type ) 
    {
    case CegoFactor::EXPR:
    {
	_pExpr->setQueryManager(pTabMng);
	break;
    }
    case CegoFactor::FUNCTION:
    {
	_pFunction->setQueryManager(pTabMng);
	break;
    }
    case CegoFactor::AGGREGATION:
    {
	_pAggr->setQueryManager(pTabMng);
	break;
    }
    case CegoFactor::QUERY:
    {
	_pSelect->setTableManager(pTabMng);
	break;
    }
    case CegoFactor::CASECOND:
    {
	_pCaseCond->setQueryManager(pTabMng);
	break;
    }
    case CegoFactor::CONDITION:
    {
	if ( _pCond )
	{
	    _pCond->setQueryManager(pTabMng);
	}
	break;;
    }
    case CegoFactor::FETCH:
    case CegoFactor::CONSTVAL:
    case CegoFactor::VAR:
    case CegoFactor::ATTR:
	break;
	
    }
}

void CegoFactor::setTabSetId(unsigned tabSetId)
{
    switch ( _type ) 
    {
    case EXPR:
    {
	_pExpr->setTabSetId(tabSetId);
	break;
    }
    case FUNCTION:
    {
	_pFunction->setTabSetId(tabSetId);
	break;
    }
    case AGGREGATION:
    {
	_pAggr->setTabSetId(tabSetId);
	break;
    }
    case QUERY:
    {
	_pSelect->setTabSetId(tabSetId);
	break;
    }
    case CASECOND:
    {
	_pCaseCond->setTabSetId(tabSetId);
	break;
    }
    case CONDITION:
    {
	if ( _pCond )
	    _pCond->setTabSetId(tabSetId);
	break;
    }
    default:
	break;
    }
}

void CegoFactor::clearAttrCache()
{
    if ( _pAttrDesc )
	_flaCached = false;   
    if ( _pExpr )
	_pExpr->clearAttrCache();
    if ( _pFunction )
	_pFunction->clearAttrCache();
    if ( _pAggr )
        _pAggr->clearAttrCache();
    if ( _pCaseCond )
	_pCaseCond->clearAttrCache();
    if ( _pCond )
	_pCond->clearAttrCache();
}

void CegoFactor::getFunctionList(SetT<CegoObject>& funcList)
{
    if ( _type == FUNCTION )
    {
	funcList.Insert(CegoObject(CegoObject::PROCEDURE, _pFunction->getName(), _pFunction->getTabSetId()));
    }
}

CegoFactor& CegoFactor::operator = ( const CegoFactor& pf)
{
    _fv = pf._fv;
    _varName = pf._varName;
    _pAttrDesc = pf._pAttrDesc;
    _isAttrRef = pf._isAttrRef;
    _pExpr = pf._pExpr;
    _pFetch = pf._pFetch;
    _pFunction = pf._pFunction;
    _pAggr = pf._pAggr;
    _pSelect = pf._pSelect;
    _type = pf._type;
    _pCaseCond = pf._pCaseCond;
    _pCond = pf._pCond;
    _flaCached = pf._flaCached;
    return (*this);
}

bool CegoFactor::checkConst() const
{
    return _type == CONSTVAL;
}

bool CegoFactor::checkVar(Chain& var) const
{
    if ( _type == VAR )
    {
	var = _varName;
	return true;
    }
    return false;
}

CegoAttrDesc* CegoFactor::checkAttr() const
{
    if ( _type == ATTR )
    {
	return _pAttrDesc;
    }
    return 0;
}

CegoCondition* CegoFactor::checkCondition() const
{
    if ( _type == CONDITION )
    {
	return _pCond;
    }
    return 0;
}


bool CegoFactor::checkLob(CegoFieldValue& fv, CegoProcBlock *pBlock)
{
    switch ( _type )
    {
    case CONSTVAL:
    {
	if ( _fv.getType() == BLOB_TYPE || _fv.getType() == CLOB_TYPE )
	{
	    fv = _fv;
	    return true;
	}
	break;
    }
    case VAR:
    {
	CegoFieldValue fv;
	if ( pBlock )
	{
	    fv = pBlock->getValue(_varName);
	    if ( fv.getType() == BLOB_TYPE || fv.getType() == CLOB_TYPE )
	    {
		return true;		
	    }
	}
	break;
    }
    case EXPR:
    case FETCH:
    case ATTR:
    case FUNCTION:
    case QUERY:
    case AGGREGATION:
    case CASECOND:
    case CONDITION:
	return false;
    }
    return false;
}

void CegoFactor::getSelectQueryList(ListT<CegoSelect*>& queryList)
{
    if ( _pSelect )
	queryList.Insert(_pSelect);
    if ( _pCaseCond )
	_pCaseCond->getSelectQueryList(queryList);
    if ( _pCond )
	_pCond->getSelectQueryList(queryList);		 
}

CegoAttrDesc* CegoFactor::getAttr() const
{
    return _pAttrDesc;
}

CegoFunction* CegoFactor::getFunction() const
{
    return _pFunction;
}

CegoAggregation* CegoFactor::getAggregation() const
{
    return _pAggr;
}

CegoSelect* CegoFactor::getSelect() const
{
    return _pSelect; 
}

CegoCaseCond* CegoFactor::getCaseCond() const
{
    return _pCaseCond;
}

CegoCondition* CegoFactor::getCondition() const
{
    return _pCond;
}

CegoCondition* CegoFactor::grapCondition()
{
    CegoCondition *pCond = _pCond;
    _pCond = 0;
    return pCond;
}

void CegoFactor::getFieldList(ListT<CegoField>& fl, ListT<CegoField>** pFLA) const
{
    switch ( _type )
    {	
    case CegoFactor::ATTR:
    {
	if ( pFLA == 0)
	{
	    Chain msg = Chain("Cannot get value for attribute " + _pAttrDesc->toChain());
	    throw Exception(EXLOC, msg);
	}
	
	unsigned i=0;
	CegoField* pF = 0;
	while ( pFLA[i] && pF == 0 )
	{		    
	    if ( ( pF = pFLA[i]->Find(CegoField(_pAttrDesc->getTableName(), _pAttrDesc->getAttrName()))) != 0 )
	    {
		fl.Insert(*pF);	       
	    }
	    i++;
	}
	break;
    }
    case CegoFactor::EXPR:
    {
	_pExpr->getFieldList(fl, pFLA);
	break;
    }
    case CegoFactor::FUNCTION:
    {
	_pFunction->getFieldList(fl, pFLA);
	break;
    }
    case CegoFactor::AGGREGATION:
    {
	if ( _pAggr->getExpr() )
	    _pAggr->getExpr()->getFieldList(fl, pFLA);
	break;
    }
    case CegoFactor::CASECOND:
    {
	_pCaseCond->getFieldList(fl, pFLA);
	break;
    }
    case CegoFactor::CONDITION:
    {
	_pCond->getFieldList(fl, pFLA);
	break;
    }
    case CegoFactor::QUERY:
    {
	_pSelect->getFieldList(fl, pFLA);
	break;
    }
    case CONSTVAL:
    case VAR:
    case FETCH:
	break;
    }
}

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

    switch ( _type )
    {	
    case CegoFactor::ATTR:
    {
	attrList.Insert(_pAttrDesc);
	break;
    }
    case CegoFactor::EXPR:
    {
	attrList = _pExpr->getAttrRefList();
	break;
    }
    case CegoFactor::FUNCTION:
    {
	attrList = _pFunction->getAttrRefList();
	break;
    }
    case CegoFactor::AGGREGATION:
    {
	if ( _pAggr->getExpr() )
	    attrList = _pAggr->getExpr()->getAttrRefList();
	break;
    }
    case CegoFactor::QUERY:
    {
	attrList = _pSelect->getAttrRefList();
	break;
    }
    case CegoFactor::CASECOND:
    {
	attrList = _pCaseCond->getAttrRefList();
	break;
    }
    case CegoFactor::CONDITION:
    {
	attrList = _pCond->getAttrRefList();
	break;
    }
    case CONSTVAL:
    case VAR:
    case FETCH:
	break;
    }
    return attrList;
}

unsigned CegoFactor::evalReferences(CegoContentObject *pCO, const ListT<CegoField>& fl)
{
    unsigned refCount = 0;

    switch ( _type )
    {
    case CegoFactor::ATTR:
    {
	refCount += _pAttrDesc->evalReferences(pCO, fl);
	break;
    }
    case CegoFactor::EXPR:
    {
	refCount += _pExpr->evalReferences(pCO, fl);
	break;
    }
    case CegoFactor::FUNCTION:
    {
	refCount += _pFunction->evalReferences(pCO, fl);
	break;
    }
    case CegoFactor::AGGREGATION:
    {
	if ( _pAggr->getExpr() )
	{
	    refCount += _pAggr->getExpr()->evalReferences(pCO, fl);
	}
	break;
    }
    case CegoFactor::QUERY:
    {
	// reset of parent join buf is done via cleanUp
	// _pSelect->setParentJoinBuf();
	_pSelect->prepare();
	refCount += _pSelect->evalExtTableReferences(pCO, fl);
	break;
    }
    case CegoFactor::CASECOND:
    {
	refCount += _pCaseCond->evalReferences(pCO, fl);
	break;
    }
    case CegoFactor::CONDITION:
    {
	refCount += _pCond->evalReferences(pCO, fl);
	break;
    }
    case CONSTVAL:
    case VAR:
    case FETCH:
	break;
    }
    return refCount;
}

CegoField CegoFactor::evalField(const ListT<CegoField>& fl, bool graceful) const
{
    CegoField f;

    switch ( _type )
    {
    case CegoFactor::CONSTVAL:
    {
	f = CegoField("CONST", "CONST", "CONST", _fv.getType(), _fv.getLength(), _fv.getDim() );
	break;
    }
    case CegoFactor::EXPR:
    {
	return _pExpr->evalField(fl, graceful);
    }
    case CegoFactor::FETCH:
    {
	f = CegoField("FETCH", "FETCH", "FETCH", BOOL_TYPE, 1 );
	break;
    }
    case CegoFactor::VAR:
    {
	f = CegoField("VAR", "VAR", "VAR", VARCHAR_TYPE, 20 );
	break;
    }
    case CegoFactor::ATTR:
    {
	if ( fl.Size() == 0 || graceful == true )
	{       	
	    f = CegoField(_pAttrDesc->getTableName(), 
			  _pAttrDesc->getAttrName());	    
	}
	else
	{
	    
	    CegoField *pF = fl.Find(CegoField(_pAttrDesc->getTableName(), _pAttrDesc->getAttrName()));
	    if ( pF )
	    {
		f = CegoField(_pAttrDesc->getTableName(), 
			      _pAttrDesc->getTableName(),
			      _pAttrDesc->getAttrName(),
			      pF->getType(),
			      pF->getLength(),
			      pF->getDim());
	    }
	    else
	    {
		Chain msg("Unknown attribute field <" + _pAttrDesc->getTableName() + "." + _pAttrDesc->getAttrName() + ">");
		throw Exception(EXLOC, msg);
	    }
	}
	break;
    }
    case CegoFactor::FUNCTION:
    {
	f = CegoField("FUNC", "FUNC", _pFunction->toChain(0), _pFunction->getReturnType(), _pFunction->getReturnTypeLen(fl));
	f.setDim(_pFunction->getReturnTypeDim());
	_pFunction->cleanUp();
	break;
    }
    case CegoFactor::AGGREGATION:
    {
	if ( _pAggr->getExpr() )
	{
	    CegoField af = _pAggr->getExpr()->evalField(fl);
	    if ( _pAggr->getType() == CegoAggregation::COUNT )
	    {
		f = CegoField("AGGR", "AGGR", _pAggr->toChain(0), LONG_TYPE, sizeof(long long));
	    }
	    else
	    {
		f = CegoField("AGGR", "AGGR", _pAggr->toChain(0), af.getType(), af.getLength(), af.getDim() );
	    }
	}
	else
	{
	    // must be count(*)
	    f = CegoField("AGGR", "AGGR", _pAggr->toChain(0), LONG_TYPE, sizeof(long long));
	}
	break;
    }
    case CegoFactor::QUERY:
    {
	ListT<CegoField> schema;
	_pSelect->getSchema(schema);
	CegoField *pF = schema.First();
	if ( pF )
	    f = *pF;
	break;
    }
    case CegoFactor::CASECOND:
    {
	return _pCaseCond->evalField(fl, graceful);
    }
    case CegoFactor::CONDITION:
    {
	return _pCond->evalField(fl, graceful);
    }
    
    default:
	break;
    }
    return f;
}

CegoFieldValue CegoFactor::evalFieldValue(ListT<CegoField>** pFLA, CegoProcBlock *pBlock)
{    
    switch ( _type )
    {
    case CONSTVAL:
    {
	_fv.setup();
	return _fv;
    }
    case EXPR:
    {
	return _pExpr->evalFieldValue(pFLA, pBlock);
    }
    case FETCH:
    {
	char *pC = new (char);
	*pC = 1;
	CegoFieldValue fv(BOOL_TYPE, pC, 1, true);

	_pFetch->setBlock(pBlock);
	
	if ( _pFetch->fetch() )
	    *pC = 1;
	else
	    *pC = 0;

	return fv;
    }
    case VAR:
    {
	CegoFieldValue fv;
	if ( pBlock )
	{
	    fv = pBlock->getValue(_varName);
	}
	return fv;
    }
    case CegoFactor::ATTR:
    {
	if ( pFLA == 0 )
	{
	    Chain msg = Chain("Cannot get value for attribute " + _pAttrDesc->toChain());
	    throw Exception(EXLOC, msg);
	}
	
	if ( _flaCached )
	{
	    // cout << "Using cached position " << _flaCacheArrayPos << "/" << _flaCacheFieldPos << endl;
	    return (*pFLA[_flaCacheArrayPos])[_flaCacheFieldPos].getValue();
	}
	
	CegoField *pF = 0;
	
	_flaCacheArrayPos=0;
	while ( pFLA[_flaCacheArrayPos] && pF == 0)
	{
	    CegoField *pF = pFLA[_flaCacheArrayPos]->First();

	    _flaCacheFieldPos = 0;
	    while ( pF )
	    {
		// cout << "Checking  " << pF->getTableAlias()  << "/" <<  pF->getTableName() << "/" << pF->getAttrName() << endl;
		if ( *pF == CegoField(_pAttrDesc->getTableName(), _pAttrDesc->getAttrName()))
		{
		    // cout << "Found value at position " << _flaCacheArrayPos << "/" << _flaCacheFieldPos << endl;
		    _flaCached = true;
		    return pF->getValue();
		}  
		pF = pFLA[_flaCacheArrayPos]->Next();
		_flaCacheFieldPos++;
	    }
	    _flaCacheArrayPos++;
	}
	if ( pF == 0 )
	{
	    Chain msg("Unknown attribute field <" + _pAttrDesc->getTableName() + "." + _pAttrDesc->getAttrName() + ">");
	    throw Exception(EXLOC, msg);
	}
    }
    case CegoFactor::FUNCTION:
    {
	return _pFunction->evalFieldValue(pFLA, pBlock);	
    }
    case CegoFactor::AGGREGATION:
    {
	return _pAggr->getFieldValue();	
    }
    case CegoFactor::QUERY:
    {
	try 
	{
	    _pSelect->setParentJoinBuf(pFLA);
	    _pSelect->setProcBlock(pBlock);
	    
	    _pSelect->prepare();

	    _pSelect->reset();

	    ListT<CegoField> fl;

	    CegoFieldValue val;

	    if ( ! _pSelect->nextTuple(fl) )
	    {
		_pSelect->reset();
		return CegoFieldValue();
	    }
	    else
	    {
		// if fetch result is just one, next call of nextTuple will complete fetch results
		// and an entry can be added to query cache ( if enabled ) 

		// before, we have to save value to local copy
		CegoField *pSF = fl.First();
		val = pSF->getValue().getLocalCopy();

		ListT<CegoField> nfl;		
		_pSelect->nextTuple(nfl);
	    }
	    
	    _pSelect->reset();
	    _pSelect->setParentJoinBuf();
	    
	    return val;
	}
	catch ( Exception e ) 
	{
	    Chain msg;
	    e.pop(msg);
	    _pSelect->cleanUp();	    
	    throw Exception(EXLOC, msg);
	}
    }
    case CegoFactor::CASECOND:
    {
	return _pCaseCond->evalFieldValue(pFLA, pBlock);
    }
    case CegoFactor::CONDITION:
    {
	return _pCond->evalFieldValue(pFLA, pBlock);
    }
    default:
        throw Exception(EXLOC, Chain("Unknown factor type"));
    }
}

ListT<CegoAggregation*> CegoFactor::getAggregationList()
{
    ListT<CegoAggregation*> aggList;

    switch ( _type )
    {
    case CegoFactor::ATTR:
    case CegoFactor::CONSTVAL:
    case CegoFactor::VAR:
    {
	// nothing to add
	break;
    }
    case CegoFactor::EXPR:
    {
	aggList = _pExpr->getAggregationList();
	break;
    }
    case CegoFactor::FUNCTION:
    {
	aggList = _pFunction->getAggregationList();
	break;
    }
    case CegoFactor::QUERY:
    {
	// nothing to add
	break;
    }
    case CegoFactor::CASECOND:
    {
	aggList = _pCaseCond->getAggregationList();
	break;
    }
    case CegoFactor::CONDITION:
    {
	aggList = _pCond->getAggregationList();
	break;
    }
    case CegoFactor::FETCH:
    {
	// nothing to add
	break;
    }
    case CegoFactor::AGGREGATION:
    {
	aggList.Insert ( _pAggr );
	break;
    }
    }
    return aggList;
}

CegoExpr* CegoFactor::getExpr() const
{
    return _pExpr;
}

const CegoFactor::FacType CegoFactor::getType() const
{
    return _type;
}

const Chain& CegoFactor::getVarName() const
{
    return _varName;
}

const CegoFieldValue& CegoFactor::getFieldValue() const
{
    return _fv;
}

CegoFactor* CegoFactor::clone(bool isAttrRef)
{
    switch ( _type ) 
    {
    case CegoFactor::ATTR:
    {
	if ( isAttrRef )
	{
	    return ( new CegoFactor ( _pAttrDesc, true ));
	}
	else
	    return ( new CegoFactor( _pAttrDesc->clone()));
    }
    case CegoFactor::CONSTVAL:
    {
	return ( new CegoFactor( _fv ) );
    }
    case CegoFactor::VAR:
    {
	return ( new CegoFactor( _varName ) );
    }
    case CegoFactor::EXPR:
    {
	return ( new CegoFactor( _pExpr->clone(isAttrRef) ) );
    }
    case CegoFactor::FUNCTION:
    {
	return ( new CegoFactor( _pFunction->clone(isAttrRef) ) );
    }
    case CegoFactor::AGGREGATION:
    {
	return ( new CegoFactor( _pAggr->clone(isAttrRef) ) );
    }
    case CegoFactor::QUERY:
    {
	return ( new CegoFactor( _pSelect->clone(isAttrRef) ) );
    }
    case CegoFactor::CASECOND:
    {
	return ( new CegoFactor( _pCaseCond->clone(isAttrRef) ) );
    }
    case CegoFactor::CONDITION:
    {
	return ( new CegoFactor( _pCond->clone(isAttrRef) ) );
    }
    case CegoFactor::FETCH:
	throw Exception(EXLOC, "Clone of fetch not implemented");
    }
    return 0;
}

Chain CegoFactor::getId(CegoProcBlock *pBlock) const
{
    Chain s;
    switch (_type)
    {
    case CegoFactor::CONSTVAL:
    {
	s = _fv.getId();
	break;
    }
    case CegoFactor::ATTR:
    {
	s = _pAttrDesc->getId();
	break;
    }
    case CegoFactor::VAR:
    {
	CegoFieldValue fv;
	if ( pBlock )
	{
	    fv = pBlock->getValue(_varName);
	}
	s = fv.toChain();
	break;
    }
    case CegoFactor::EXPR:
    {
	s = Chain("(") + _pExpr->getId(pBlock) + Chain(")");
	break;
    }
    case CegoFactor::FETCH:
    {
	s = _pFetch->toChain();
	break;
    }
    case CegoFactor::AGGREGATION:
    {
	s = _pAggr->getId(pBlock);
	break;
    }
    case CegoFactor::FUNCTION:
    {
	s = _pFunction->getId(pBlock);
	break;
    }
    case CegoFactor::QUERY:
    {
	s = Chain("(") + _pSelect->getQueryId() + Chain(")");
	break;
    }
    case CegoFactor::CASECOND:
    {
	s = _pCaseCond->getId(pBlock);
	break;
    }
    case CegoFactor::CONDITION:
    {
	s = _pCond->getId(pBlock);
	break;
    }
    }
    return s;
}

Chain CegoFactor::toChain(unsigned defTabSetId, const Chain& indent) const
{
    Chain s;
    
    switch (_type)
    {
    case CegoFactor::CONSTVAL:
	s = _fv.toChain();
	break;
    case CegoFactor::ATTR:
	s = _pAttrDesc->toChain();
	break;
    case CegoFactor::VAR:
	s = Chain(":") + _varName;
	break;
    case CegoFactor::EXPR:
	s = Chain("(") + _pExpr->toChain(defTabSetId, indent) + Chain(")");
	break;
    case CegoFactor::FETCH:
	s = _pFetch->toChain();
	break;
    case CegoFactor::AGGREGATION:
	s = _pAggr->toChain(defTabSetId);
	break;
    case CegoFactor::FUNCTION:
	s = _pFunction->toChain(defTabSetId);
	break;
    case CegoFactor::QUERY:
	s = Chain("( ") + _pSelect->toChain(defTabSetId, indent + Chain(" ")) + Chain(" )");
	break;
    case CegoFactor::CASECOND:
	s = _pCaseCond->toChain(defTabSetId);
	break;
    case CegoFactor::CONDITION:
	s = Chain("(") + _pCond->toChain(defTabSetId) + Chain(")");
	break;
    }
    return s;
}

Chain CegoFactor::dbFormat(CegoDatabaseFormater *pForm) const
{
    return pForm->formatFactor(_type, _fv, _pAttrDesc, _varName, _pExpr, _pFetch, _pAggr, _pFunction, _pSelect, _pCaseCond, _pCond);
}

void CegoFactor::encode(char *buf, CegoProcBlock *pBlock)
{    
    char* pE = (char*)buf;

    switch (_type )
    {
    case CegoFactor::CONSTVAL:
    {
	memcpy( pE, &_type, sizeof(CegoFactor::FacType));
	pE = pE + sizeof(CegoFactor::FacType);
	_fv.encode(pE);
	pE = pE + _fv.getEncodingLength();
	break;
    }
    case CegoFactor::ATTR:
    {
	memcpy( pE, &_type, sizeof(CegoFactor::FacType));
	pE = pE + sizeof(CegoFactor::FacType);
	_pAttrDesc->encode(pE);
	pE = pE + _pAttrDesc->getEncodingLength();
	break;
    }
    case CegoFactor::VAR:
    {
	// cast to const
	
	CegoFactor::FacType type = CegoFactor::CONSTVAL;
	memcpy( pE, &type, sizeof(CegoFactor::FacType));
	pE = pE + sizeof(CegoFactor::FacType);

	CegoFieldValue fv;	
	if ( pBlock )
	{
	    fv = pBlock->getValue(_varName);
	}
	
	fv.encode(pE);
	pE = pE + fv.getEncodingLength();
	break;
	
    }
    case CegoFactor::EXPR:
    {
	memcpy( pE, &_type, sizeof(CegoFactor::FacType));
	pE = pE + sizeof(CegoFactor::FacType);
	_pExpr->encode(pE, pBlock);
	pE = pE + _pExpr->getEncodingLength(pBlock);
	break;
    }
    case CegoFactor::FETCH:
    {
	throw Exception(EXLOC, "No encoding supported for fetch");
	break;
    }
    case CegoFactor::CASECOND:
    {
	memcpy( pE, &_type, sizeof(CegoFactor::FacType));
	pE = pE + sizeof(CegoFactor::FacType);
	_pCaseCond->encode(pE, pBlock);
	pE = pE + _pCaseCond->getEncodingLength(pBlock);
	break;
    }
    case CegoFactor::CONDITION:
    {
	memcpy( pE, &_type, sizeof(CegoFactor::FacType));
	pE = pE + sizeof(CegoFactor::FacType);
	_pCond->encode(pE, pBlock);
	pE = pE + _pCond->getEncodingLength(pBlock);
	break;
    }
    case CegoFactor::AGGREGATION:
    {
	memcpy( pE, &_type, sizeof(CegoFactor::FacType));
	pE = pE + sizeof(CegoFactor::FacType);
	_pAggr->encode(pE, pBlock);
	pE = pE + _pAggr->getEncodingLength(pBlock);
	break;
    }
    case CegoFactor::FUNCTION:
    {
	memcpy( pE, &_type, sizeof(CegoFactor::FacType));
	pE = pE + sizeof(CegoFactor::FacType);
	_pFunction->encode(pE, pBlock);
	pE = pE + _pFunction->getEncodingLength(pBlock);
	break;
    }
    case CegoFactor::QUERY:
    {
	memcpy( pE, &_type, sizeof(CegoFactor::FacType));
	pE = pE + sizeof(CegoFactor::FacType);
	_pSelect->encode(pE, pBlock);
	pE = pE + _pSelect->getEncodingLength(pBlock);
	break;
    }
    }
}

void CegoFactor::decode(char *buf)
{
    char* pE = (char*)buf;

    memcpy( &_type, pE, sizeof(CegoFactor::FacType));
    pE = pE + sizeof(CegoFactor::FacType);
    
    switch (_type )
    {
    case CegoFactor::CONSTVAL:
    {
	_fv.decode(pE);
	pE = pE + _fv.getEncodingLength();
	break;
    }
    case CegoFactor::ATTR:
    {
	_pAttrDesc = new CegoAttrDesc();
	_pAttrDesc->decode(pE);
	pE = pE + _pAttrDesc->getEncodingLength();
	break;
    }
    case CegoFactor::VAR:
    {
	throw Exception(EXLOC, "No decoding supported for var");
	break;
    }
    case CegoFactor::EXPR:
    {
	_pExpr = new CegoExpr(pE);
	pE = pE + _pExpr->getEncodingLength();
	break;
    }
    case CegoFactor::FETCH:
    {
	throw Exception(EXLOC, "No decoding supported for fetch");
	break;
    }
    case CegoFactor::CASECOND:
    {
	_pCaseCond = new CegoCaseCond(pE);
	pE = pE + _pCaseCond->getEncodingLength();
	break;
    }
    case CegoFactor::CONDITION:
    {
	_pCond = new CegoCondition(pE);
	pE = pE + _pCond->getEncodingLength();
	break;
    }
    case CegoFactor::AGGREGATION:
    {
	_pAggr = new CegoAggregation(pE);
	pE = pE + _pAggr->getEncodingLength();
	break;
    }
    case CegoFactor::FUNCTION:
    {
	_pFunction = new CegoFunction(pE);
	pE = pE + _pFunction->getEncodingLength();
	break;
    }
    case CegoFactor::QUERY:
    {
	_pSelect = new CegoSelect(pE);
	pE = pE + _pSelect->getEncodingLength();
	break;
    }
    }
}

unsigned CegoFactor::getEncodingLength(CegoProcBlock *pBlock) const
{   
    unsigned len = 0;

    len += sizeof(CegoFactor::FacType);

    switch (_type )
    {
    case CegoFactor::CONSTVAL:
    {
	len += _fv.getEncodingLength();
	break;
    }
    case CegoFactor::ATTR:
    {
	len += _pAttrDesc->getEncodingLength();
	break;
    }
    case CegoFactor::VAR:
    {
	CegoFieldValue fv;

	if ( pBlock )
	{
	    fv = pBlock->getValue(_varName);
	}
	
	len += fv.getEncodingLength();
	break;
    }
    case CegoFactor::EXPR:
    {
	len += _pExpr->getEncodingLength(pBlock);
	break;
    }
    case CegoFactor::FETCH:
    {
	// no encoding supported for procedures
	break;
    }
    case CegoFactor::CASECOND:
    {
	len += _pCaseCond->getEncodingLength(pBlock);
	break;
    }
    case CegoFactor::CONDITION:
    {
	len += _pCond->getEncodingLength(pBlock);
	break;
    }
    case CegoFactor::AGGREGATION:
    {
	len += _pAggr->getEncodingLength(pBlock);
	break;
    }
    case CegoFactor::FUNCTION:
    {
	len += _pFunction->getEncodingLength(pBlock);
	break;
    }
    case CegoFactor::QUERY:
    {
	len +=_pSelect->getEncodingLength(pBlock);
	break;
    }
    }
    
    return len;    
}

void CegoFactor::getPlanList(ListT<Element*>& planList)
{
    if ( _pSelect )
	planList.Insert(_pSelect->getPlan());
    if ( _pCaseCond )
	_pCaseCond->getPlanList(planList);
    if ( _pCond )
	_pCond->getPlanList(planList);
}

ostream& operator << (ostream& s, const CegoFactor& pf)
{
    s << pf.toChain(0, Chain());
    return s;
}

CegoFactor* CegoFactor::map(const Chain& viewAlias, const ListT<CegoExpr*>& exprList) const
{

    switch ( _type ) 
    {
    case CegoFactor::ATTR:
    {	
	CegoExpr **pExpr = exprList.First();
	while ( pExpr )
	{
	    if ( (*pExpr)->getAlias() == _pAttrDesc->getAttrName() )
		return new CegoFactor ( (*pExpr)->clone() );
	    pExpr = exprList.Next();
	}
	return 0;
    }
    case CegoFactor::CONSTVAL:
    {
	return ( new CegoFactor( _fv ) );
    }
    case CegoFactor::VAR:
    {
	return ( new CegoFactor( _varName ) );
    }
    case CegoFactor::EXPR:
    {
	CegoExpr* pMapExpr = _pExpr->map(viewAlias, exprList);
	if ( pMapExpr )
	    return new CegoFactor( pMapExpr );
	return 0;
    }
    case CegoFactor::FUNCTION:
    {
	CegoFunction* pMapFunction = _pFunction->map(viewAlias, exprList);
	if ( pMapFunction )
	    return new CegoFactor( pMapFunction );
	return 0;
    }
    case CegoFactor::AGGREGATION:
    {
	return 0;
    }
    case CegoFactor::QUERY:
    {
	return 0;
    }
    case CegoFactor::CASECOND:
    {
	CegoCaseCond* pMapCaseCond = _pCaseCond->map(viewAlias, exprList);
	if ( pMapCaseCond )
	    return new CegoFactor( pMapCaseCond );
	return 0;	
    }
    case CegoFactor::CONDITION:
    {
	CegoCondition* pMapCond = _pCond->map(viewAlias, exprList);
	if ( pMapCond )
	    return new CegoFactor( pMapCond );
	return 0;
    }
    case CegoFactor::FETCH:
	return 0;
	
    }
    return 0;
}
