///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoFactor.cc
// -------------
// Cego procedure factor structure class 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: CegoFactor
// 
// Description: Container class to describe a factor element
//
// Status: QS-2.6
// 
///////////////////////////////////////////////////////////////////////////////

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

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

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

CegoFactor::CegoFactor(char* buf, CegoDistManager *pGTM)
{
    _pAttrDesc = 0;
    _pExpr = 0;
    _pFetch = 0;
    _pBlock = 0;
    _pAggr = 0;
    _pFunction = 0;
    _pSelect = 0;
    _fla = 0;
    _pCaseCond = 0;

    _flaCached = false;

    decode(buf, pGTM);
}

CegoFactor::CegoFactor(Element* pFactorElement, CegoDistManager *pGTM)
{
    _pAttrDesc = 0;
    _pExpr = 0;
    _pFetch = 0;
    _pBlock = 0;
    _pAggr = 0;
    _pFunction = 0;
    _pSelect = 0;
    _fla = 0;
    _pCaseCond = 0;

    _flaCached = false;

    fromElement(pFactorElement, pGTM);
}

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

CegoFactor::CegoFactor(const Chain& varName)
{
    _type = VAR;
    _varName = varName;
    _pAttrDesc = 0;
    _pExpr = 0;
    _pFetch = 0;
    _pBlock = 0;
    _pAggr = 0;
    _pFunction = 0;
    _pSelect = 0;
    _fla = 0;
    _pCaseCond = 0;

    _flaCached = false;
}

CegoFactor::CegoFactor(const CegoFieldValue& fv)
{
    _type = CONSTVAL;
    _fv = fv;
    _pAttrDesc = 0;
    _pExpr = 0;
    _pBlock = 0;
    _pFetch = 0;
    _pAggr = 0;
    _pFunction = 0;
    _pSelect = 0;
    _fla = 0;
    _pCaseCond = 0;

    _flaCached = false;
}

CegoFactor::CegoFactor(CegoExpr *pExpr)
{
    _type = EXPR;
    _pAttrDesc = 0;
    _pExpr = pExpr;
    _pFetch = 0;
    _pBlock = 0;
    _pAggr = 0;
    _pFunction = 0;
    _pSelect = 0;
    _fla = 0;
    _pCaseCond = 0;

    _flaCached = false;
}

CegoFactor::CegoFactor(CegoProcFetch *pFetch)
{
    _type = FETCH;
    _pAttrDesc = 0;
    _pExpr = 0;
    _pFetch = pFetch;
    _pBlock = 0;
    _pAggr = 0;
    _pFunction = 0;
    _pSelect = 0;
    _fla = 0;
    _pCaseCond = 0;

    _flaCached = false;
}

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

    _flaCached = false;
}

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

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

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

CegoFactor::CegoFactor(CegoCaseCond* pCaseCond)
{
    _type = CASECOND;
    _pBlock = 0;
    _pAttrDesc = 0;
    _pExpr = 0;
    _pFetch = 0;
    _pAggr = 0;
    _fla = 0;
    _pFunction = 0;
    _pSelect = 0;
    _pCaseCond = pCaseCond;
    _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;
}    
    
void CegoFactor::setBlock(CegoProcBlock *pBlock)
{
    switch ( _type ) 
    {
    case VAR:
    {
	_pBlock = pBlock;
	break;
    }
    case EXPR:
    {
	_pExpr->setBlock(pBlock);
	break;
    }
    case FETCH:
    {
	_pFetch->setBlock(pBlock);
	break;
    }
    case FUNCTION:
    {
	_pFunction->setBlock(pBlock);
	break;
    }
    case AGGREGATION:
    {
	_pAggr->setBlock(pBlock);
	break;
    }
    case QUERY:
    {
	_pSelect->setProcBlock(pBlock);
	_pSelect->prepare();
	break;
    }
    case CASECOND:
    {
	_pCaseCond->setBlock(pBlock);
	break;
    }
    case CONSTVAL:
    case ATTR:
    {
	// nothing to do
	break;
    }
    }
}

void CegoFactor::clearAttrCache()
{
    // if ( _pAttrDesc )
    // cout << "Clearing cache for " << _pAttrDesc->toChain() << endl;

    if ( _pAttrDesc )
	_flaCached = false;
    if ( _pExpr )
	_pExpr->clearAttrCache();
    if ( _pFunction )
	_pFunction->clearAttrCache();
    if ( _pAggr )
        _pAggr->clearAttrCache();
    if ( _pCaseCond )
	_pCaseCond->clearAttrCache();
}

bool CegoFactor::getTableDesc(CegoTableDesc& td) const
{
    if ( _type == ATTR )
    {
	td.setTableAlias(_pAttrDesc->getTableName());
	return true;
    }
    return false;
}

void CegoFactor::setFieldListArray(ListT<CegoField> *fla, int size)
{
    // cout << "Setting field list of size " << size  << endl;
    switch ( _type ) 
    {
    case ATTR:
    {
	_fla = fla;
	_flaSize = size;
	break;
    }
    case EXPR:
    {
	_pExpr->setFieldListArray(fla, size);
	break;
    }
    case FUNCTION:
    {
	_pFunction->setFieldListArray(fla, size);
	break;
    }
    case AGGREGATION:
    {
	_pAggr->setFieldListArray(fla, size);
	break;
    }
    case QUERY:
    {
	_pSelect->setParentJoinBuf(fla, size);
	_pSelect->prepare(); // not necessary
	break;
    }
    case CASECOND:
    {
	_pCaseCond->setFieldListArray(fla, size);
	break;
    }
    default:
	break;
    }
}

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;
    _pBlock = pf._pBlock;
    _pCaseCond = pf._pCaseCond;
    _flaCached = pf._flaCached;

    return (*this);
}

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;
}

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;
}

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

    ListT<CegoField> fl;

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

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;
    }
    default:
	break;

    }
    return attrList;
}

int CegoFactor::evalReferences(CegoContentObject *pCO, const ListT<CegoField>& fl)
{
    int 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:
    {
	_pSelect->prepare();
	refCount += _pSelect->evalExtTableReferences(pCO, fl);
	break;
    }
    case CegoFactor::CASECOND:
    {
	refCount += _pCaseCond->evalReferences(pCO, fl);
	break;
    }
    default:
	break;

    }

    return refCount;

}

CegoField CegoFactor::evalField() const
{

    CegoField f;

    switch ( _type )
    {
    case CegoFactor::CONSTVAL:
    {
	f = CegoField("CONST", "CONST", "CONST", _fv.getType(), _fv.getLength() );
	break;
    }
    case CegoFactor::EXPR:
    {
	return _pExpr->evalField();
    }
    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 ( _fla == 0)
	{
       	
	    f = CegoField(_pAttrDesc->getTableName(), 
			  _pAttrDesc->getAttrName());
	    
	    // Chain msg = Chain("Fieldlist not set for " + _attrDesc.toChain());
	    // throw Exception(EXLOC, msg);
	}
	else
	{
	    CegoField *pF = 0;
	    
	    int i=0;
	    while ( i < _flaSize && pF == 0)
	    {
		if ( ( pF = _fla[i].Find(CegoField(_pAttrDesc->getTableName(), _pAttrDesc->getAttrName()))) != 0 )
		{
		    f = CegoField(_pAttrDesc->getTableName(), 
				  _pAttrDesc->getTableName(),
				  _pAttrDesc->getAttrName(),
				  pF->getType(),
				  pF->getLength());
		}
		i++;
	    }
	    
	    if ( pF == 0 )
	    {
		Chain msg("Unknown attribute field <" + _pAttrDesc->getTableName() + "." + _pAttrDesc->getAttrName() + ">");
		throw Exception(EXLOC, msg);
	    }
	}
	
	break;
    }
    case CegoFactor::FUNCTION:
    {
	f = CegoField("FUNC", "FUNC", _pFunction->toChain(), VARCHAR_TYPE, 20 );
	break;
    }
    case CegoFactor::AGGREGATION:
    {
	
	if ( _pAggr->getExpr() )
	{
	    CegoField af = _pAggr->getExpr()->evalField();
	    f = CegoField("AGGR", "AGGR", _pAggr->toChain(), af.getType(), af.getLength() );
	}
	else
	{
	    // must be count(*)
	    f = CegoField("AGGR", "AGGR", _pAggr->toChain(), INT_TYPE,  4);
	}
	break;
    }
    case CegoFactor::QUERY:
    {
	f = CegoField("QUERY", "QUERY", Chain("select(..)"), VARCHAR_TYPE, 20 );
	break;
    }
    case CegoFactor::CASECOND:
    {
	return _pCaseCond->evalField();
    }
    default:
	break;

    }
    return f;
}

CegoFieldValue CegoFactor::evalFieldValue()
{
    switch ( _type )
    {
    case CONSTVAL:
    {
	return _fv;
    }
    case EXPR:
    {
	return _pExpr->evalFieldValue();
    }
    case FETCH:
    {
	
	char *pC = new (char);
	*pC = 1;
	CegoFieldValue fv(BOOL_TYPE, pC, 1, true);

	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 ( _flaCached )
	{
	    // cout << "Using cached field for " << _pAttrDesc->toChain() << " with pos " << _flaCacheArrayPos << " / " << _flaCacheFieldPos << endl;
	    return _fla[_flaCacheArrayPos][_flaCacheFieldPos].getValue();
	}
	if ( _fla == 0)
	{
	    Chain msg = Chain("Cannot get value for attribute " + _pAttrDesc->toChain());
	    throw Exception(EXLOC, msg);
	}
	
	CegoField *pF = 0;
	
	_flaCacheArrayPos=0;
	while ( _flaCacheArrayPos < _flaSize && pF == 0)
	{

	    CegoField *pF = _fla[_flaCacheArrayPos].First();

	    _flaCacheFieldPos = 0;
	    while ( pF )
	    {
		if ( *pF == CegoField(_pAttrDesc->getTableName(), _pAttrDesc->getAttrName()))
		{
		    _flaCached = true;
		    return pF->getValue();
		}  
		pF = _fla[_flaCacheArrayPos].Next();
		_flaCacheFieldPos++;
	    }

	    /*
	    if ( ( pF = _fla[i].Find(CegoField(_pAttrDesc->getTableName(), _pAttrDesc->getAttrName()))) != 0 )
	    {
		_pCacheField = pF;

		return pF->getValue();
	    }
	    */
	    _flaCacheArrayPos++;
	}
	
	if ( pF == 0 )
	{
	    
	    
	    /*
	    int i=0;
	    while ( i < _flaSize)
	    {
		CegoField *pF = _fla[i].First();
		while ( pF )
		{
		    cout << "Fla Field = " << pF->getTableName() << "." << pF->getAttrName() << endl;
		    pF = _fla[i].Next();
		}
		i++;
	    }
	    */
	    	    
	    
	    Chain msg("Unknown attribute field <" + _pAttrDesc->getTableName() + "." + _pAttrDesc->getAttrName() + ">");
	    throw Exception(EXLOC, msg);
	}       

    }
    case CegoFactor::FUNCTION:
    {
	return _pFunction->evalFieldValue();	
    }
    case CegoFactor::AGGREGATION:
    {
	return _pAggr->getFieldValue();	
    }
    case CegoFactor::QUERY:
    {

	try 
	{

	    // _pSelect->cleanUp();
	    _pSelect->prepare();
	    // _pSelect->reset(false);

	    ListT<CegoField> fl;

	    if ( ! _pSelect->nextTuple(fl) )
	    {	       
		_pSelect->reset(true);
		return CegoFieldValue();
	    }
	    
	    CegoField *pSF = fl.First();
	    
	    _pSelect->reset(true);
	    return pSF->getValue();
	}
	catch ( Exception e ) 
	{
	    _pSelect->cleanUp();
	    throw Exception(EXLOC, Chain("Cannot eval field value"), e);
	}
    }
    case CegoFactor::CASECOND:
    {
	return _pCaseCond->evalFieldValue();
    }
    default:
	break;

    }
}

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::FETCH:
	throw Exception(EXLOC, "Clone of fetch not implemented");
    }
    return 0;
}

Chain CegoFactor::toChain() 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() + Chain(")");
	break;
    case CegoFactor::FETCH:
	s = _pFetch->toChain();
	break;
    case CegoFactor::AGGREGATION:
	s = _pAggr->toChain();
	break;
    case CegoFactor::FUNCTION:
	s = _pFunction->toChain();
	break;
    case CegoFactor::QUERY:
	s = Chain("(") + _pSelect->toChain() + Chain(")");
	break;
    case CegoFactor::CASECOND:
	s = _pCaseCond->toChain();
	break;
    }
    return s;
}


Element* CegoFactor::toElement() const
{
    Element* pFactorElement = new Element(XML_FACTOR_ELEMENT);

    switch (_type)
    {
    case CegoFactor::CONSTVAL:
    {
	CegoTypeConverter tc;
	pFactorElement->setAttribute( XML_FACTOR_ATTR, XML_CONST_VALUE );
	pFactorElement->setAttribute( XML_TYPE_ATTR, tc.getTypeString(_fv.getType()));
	pFactorElement->setAttribute( XML_VALUE_ATTR, _fv.valAsChain() );
	break;
    }
    case CegoFactor::ATTR:
    {
	pFactorElement->setAttribute( XML_FACTOR_ATTR, XML_ATTR_VALUE );
	if ( _pAttrDesc->getTableName().length() > 0 )
	    pFactorElement->setAttribute( XML_TABLENAME_ATTR, _pAttrDesc->getTableName() );
	pFactorElement->setAttribute( XML_ATTRNAME_ATTR, _pAttrDesc->getAttrName() );
	break;
    }
    case CegoFactor::VAR:
    {
	pFactorElement->setAttribute( XML_FACTOR_ATTR, XML_VAR_VALUE );
	pFactorElement->setAttribute( XML_VALUE_ATTR, _varName );
	break;
    }
    case CegoFactor::EXPR:
    {
	pFactorElement->setAttribute( XML_FACTOR_ATTR, XML_EXPR_VALUE );
	pFactorElement->addContent( _pExpr->toElement() );
	break;
    }
    case CegoFactor::FETCH:
    {
	throw Exception(EXLOC, "Cursor fetch not supported in distributed query");
    }
    case CegoFactor::CASECOND:
    {
	throw Exception(EXLOC, "case condition not supported in distributed query");
    }
    case CegoFactor::AGGREGATION:
    {
	throw Exception(EXLOC, "Aggregation not supported in distributed query");
    }
    case CegoFactor::FUNCTION:
    {
	pFactorElement->setAttribute( XML_FACTOR_ATTR, XML_FUNCTION_VALUE );
	pFactorElement->addContent( _pFunction->toElement() );
	break;
    }
    case CegoFactor::QUERY:
    {
	pFactorElement->setAttribute( XML_FACTOR_ATTR, XML_SELECT_VALUE );
	pFactorElement->addContent( _pSelect->toElement() );
	break;
    }
    }
    return pFactorElement;
}

void CegoFactor::fromElement(Element *pFactorElement, CegoDistManager* pGTM)
{

    Chain factorTypeString = pFactorElement->getAttributeValue( XML_FACTOR_ATTR );

    if ( factorTypeString == Chain(XML_CONST_VALUE) )
    {
	_type = CegoFactor::CONSTVAL;
	CegoTypeConverter tc;
	_fv = CegoFieldValue( tc.getTypeId(pFactorElement->getAttributeValue( XML_TYPE_ATTR )),
			      pFactorElement->getAttributeValue( XML_VALUE_ATTR ));
	
    }
    else if ( factorTypeString == Chain(XML_ATTR_VALUE) )
    {
	_type = CegoFactor::ATTR;
	Chain tableName = pFactorElement->getAttributeValue( XML_TABLENAME_ATTR );
	if ( tableName.length() > 0 )
	    _pAttrDesc = new CegoAttrDesc( pFactorElement->getAttributeValue( XML_TABLENAME_ATTR ),
				      pFactorElement->getAttributeValue( XML_ATTRNAME_ATTR ));
	else
	    _pAttrDesc = new CegoAttrDesc( pFactorElement->getAttributeValue( XML_ATTRNAME_ATTR ));
    }
    else if ( factorTypeString == Chain(XML_VAR_VALUE) )
    {
	_type = CegoFactor::VAR;
	_varName =  pFactorElement->getAttributeValue( XML_VALUE_ATTR );
    }
    else if ( factorTypeString == Chain(XML_EXPR_VALUE) )
    {
	_type = CegoFactor::EXPR;
	ListT<Element*> el = pFactorElement->getChildren(XML_EXPR_ELEMENT);
	Element **pEE = el.First();
	if ( pEE )
	{
	    _pExpr = new CegoExpr(*pEE, pGTM);
	}
    }
    else if ( factorTypeString == Chain(XML_FETCH_VALUE) )
    {
	throw Exception(EXLOC, "Cursor fetch not supported in distributed query");
    }
    else if ( factorTypeString == Chain(XML_AGGREGATION_VALUE) )
    {
	throw Exception(EXLOC, "Aggregation not supported in distributed query");
    }
    else if ( factorTypeString == Chain(XML_FUNCTION_VALUE) )
    {
	_type = CegoFactor::FUNCTION;
	ListT<Element*> fl = pFactorElement->getChildren(XML_FUNCTION_ELEMENT);
	Element **pFE = fl.First();
	if ( pFE )
	{
	    _pFunction = new CegoFunction(*pFE, pGTM);
	}
    }
    else if ( factorTypeString == Chain(XML_SELECT_VALUE) )
    {
	_type = CegoFactor::QUERY;
	ListT<Element*> sl = pFactorElement->getChildren(XML_SELECT_ELEMENT);
	Element **pSE = sl.First();
	if ( pSE )
	{
	    _pSelect = new CegoSelect(*pSE, pGTM);
	}
    }
}

void CegoFactor::encode(char *buf)
{
    
    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);
	pE = pE + _pExpr->getEncodingLength();
	break;
    }
    case CegoFactor::FETCH:
    {
	throw Exception(EXLOC, "No encoding supported for fetch");
	break;
    }
    case CegoFactor::CASECOND:
    {
	throw Exception(EXLOC, "No encoding supported for case condition");
    }
    case CegoFactor::AGGREGATION:
    {
	memcpy( pE, &_type, sizeof(CegoFactor::FacType));
	pE = pE + sizeof(CegoFactor::FacType);
	_pAggr->encode(pE);
	pE = pE + _pAggr->getEncodingLength();
	break;
    }
    case CegoFactor::FUNCTION:
    {
	memcpy( pE, &_type, sizeof(CegoFactor::FacType));
	pE = pE + sizeof(CegoFactor::FacType);
	_pFunction->encode(pE);
	pE = pE + _pFunction->getEncodingLength();
	break;
    }
    case CegoFactor::QUERY:
    {
	memcpy( pE, &_type, sizeof(CegoFactor::FacType));
	pE = pE + sizeof(CegoFactor::FacType);
	_pSelect->encode(pE);
	pE = pE + _pSelect->getEncodingLength();
	break;
    }
    }
}

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

    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, pGTM);
	pE = pE + _pExpr->getEncodingLength();
	break;
    }
    case CegoFactor::FETCH:
    {
	throw Exception(EXLOC, "No decoding supported for fetch");
	break;
    }
    case CegoFactor::CASECOND:
    {
	throw Exception(EXLOC, "No decoding supported for case condition");
	break;
    }
    case CegoFactor::AGGREGATION:
    {
	_pAggr = new CegoAggregation(pE, pGTM);
	pE = pE + _pAggr->getEncodingLength();
	break;
    }
    case CegoFactor::FUNCTION:
    {
	_pFunction = new CegoFunction(pE, pGTM);
	pE = pE + _pFunction->getEncodingLength();
	break;
    }
    case CegoFactor::QUERY:
    {
	_pSelect = new CegoSelect(pE, pGTM);
	pE = pE + _pSelect->getEncodingLength();
	break;
    }
    }
}

int CegoFactor::getEncodingLength() const
{
    
    int 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();
	break;
    }
    case CegoFactor::FETCH:
    {
	// no encoding supported for procedures
	break;
    }
    case CegoFactor::CASECOND:
    {
	// no encoding supported for casecond
	break;
    }
    case CegoFactor::AGGREGATION:
    {
	len += _pAggr->getEncodingLength();
	break;
    }
    case CegoFactor::FUNCTION:
    {
	len += _pFunction->getEncodingLength();
	break;
    }
    case CegoFactor::QUERY:
    {
	len +=_pSelect->getEncodingLength();
	break;
    }
    }

    return len;
    
}

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

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

