///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoPredicate-.cc
// -----------------
// Cego predicate structure class definition
//                                                 
// Design and Implementation by Bjoern Lemke               
//     
// (C)opyright 2000-2025 Bjoern Lemke
//
// IMPLEMENTATION MODULE
//
// Class: CegoPredDesc
//
// Description: The CegoPrdDesc class is a container class for the query predicate representation
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

// CEGO INCLUDES
#include "CegoPredicate.h"
#include "CegoCondition.h"
#include "CegoSelect.h"
#include "CegoXMLdef.h"
#include "CegoDatabaseFormater.h"
#include "CegoQueryHelper.h"

// POSIX INCLUDES
#include <string.h>
#include <stdlib.h>

CegoPredicate::CegoPredicate(char* buf)
{
    _pExpr1 = 0;
    _pExpr2 = 0;
    _pExpr3 = 0;
    _pC = 0;
    _pNotPred = 0;
    _isChecked = false;
    _pSelect = 0;
    _pMatcher = 0;
    decode(buf);
}

CegoPredicate::CegoPredicate(CegoExpr *pExpr1, CegoExpr* pExpr2, const CegoComparison& comp)
{
    _pExpr1 = pExpr1;
    _pExpr2 = pExpr2;
    _pExpr3 = 0;
    _comp = comp;
    _pC = 0;
    _pNotPred = 0;
    _mode = CegoPredicate::EXPRCOMP;
    _isChecked = false;
    _pSelect = 0;
    _pMatcher = 0;
}

CegoPredicate::CegoPredicate(CegoExpr *pExpr1, CegoExpr* pExpr2, CegoExpr* pExpr3 )
{
    _pExpr1 = pExpr1;
    _pExpr2 = pExpr2;
    _pExpr3 = pExpr3;
    _pC = 0;
    _pNotPred = 0;
    _mode = CegoPredicate::BETWEEN;
    _isChecked = false;
    _pSelect = 0;
    _pMatcher = 0;
}

CegoPredicate::CegoPredicate(CegoExpr *pExpr, const Chain& pattern, bool isNegated, bool isCaseSensitive)
{
    _pExpr1 = pExpr;
    _pExpr2 = 0;
    _pExpr3 = 0;
    _pattern = pattern;
    _pMatcher = 0;
        
    if ( ! isNegated && isCaseSensitive)
	_mode = CegoPredicate::ISLIKE;
    else if ( ! isNegated && isCaseSensitive)
	_mode = CegoPredicate::ISNOTLIKE;
    else if ( ! isNegated && ! isCaseSensitive)
	_mode = CegoPredicate::ISNCLIKE;
    else if ( isNegated && ! isCaseSensitive)
	_mode = CegoPredicate::ISNOTNCLIKE;
    
    _isChecked = false;
    _pSelect = 0;
    _pC = 0;
    _pNotPred = 0;
}

CegoPredicate::CegoPredicate(const CegoPredicate& p)
{
    *this = p;
}

CegoPredicate::CegoPredicate(CegoCondition *pC)
{
    _pExpr1 = 0;
    _pExpr2 = 0;
    _pExpr3 = 0;    
    _pC = pC;
    _pNotPred = 0;
    _isChecked = false;
    _pSelect = 0;
    _pMatcher = 0;
    _mode = CegoPredicate::CONDITION;
}

CegoPredicate::CegoPredicate(CegoPredicate *pNotPred)
{
    _pExpr1 = 0;
    _pExpr2 = 0;
    _pExpr3 = 0;    
    _pC = 0;
    _isChecked = false;
    _pSelect = 0;
    _pMatcher = 0;
    _pNotPred = pNotPred;
    _mode = CegoPredicate::NOTPRED;
}

CegoPredicate::CegoPredicate(CegoSelect *pSelect)
{
    _pExpr1 = 0;
    _pExpr2 = 0;
    _pExpr3 = 0;
    _pSelect = pSelect;
    _pMatcher = 0;
    _pC = 0;
    _pNotPred = 0;
    _mode = CegoPredicate::EXISTSCOMP;
    _isChecked = false;
}

CegoPredicate::CegoPredicate(CegoExpr *pExpr, ListT<CegoExpr*>& exprList, bool isNegated)
{
    _pExpr1 = pExpr;
    _pExpr2 = 0;
    _pExpr3 = 0;
    _exprList = exprList;
    _pSelect = 0;
    _pMatcher = 0;
    _pC = 0;
    _pNotPred = 0;
    if ( isNegated )
	_mode = CegoPredicate::NOTIN;
    else
	_mode = CegoPredicate::IN;
    _isChecked = false;
}

CegoPredicate::CegoPredicate(CegoExpr *pExpr, CegoSelect* pSelect, bool isNegated)
{
    _pExpr1 = pExpr;
    _pExpr2 = 0;
    _pExpr3 = 0;
    _pSelect = pSelect;
    _pMatcher = 0;
    _pC = 0;
    _pNotPred = 0;
    if ( isNegated )
	_mode = CegoPredicate::NOTINSUB;
    else
	_mode = CegoPredicate::INSUB;
    _isChecked = false;
}

CegoPredicate::CegoPredicate(CegoExpr* pExpr, bool isNull)
{
    _pExpr1 = pExpr;
    _pExpr2 = 0;
    _pExpr3 = 0;
    _pSelect = 0;
    _pMatcher = 0;
    _pC = 0;
    _pNotPred = 0;
    if  ( isNull )
	_mode = CegoPredicate::NULLCOMP;
    else
    	_mode = CegoPredicate::NOTNULLCOMP;
    _isChecked = false;
}

CegoPredicate::CegoPredicate(CegoExpr* pExpr)
{
    _pExpr1 = pExpr;
    _pExpr2 = 0;
    _pExpr3 = 0;
    _pSelect = 0;
    _pMatcher = 0;
    _pC = 0;
    _pNotPred = 0;	
    _mode = CegoPredicate::EXPRONLY;
    _isChecked = false;
}

CegoPredicate::~CegoPredicate()
{
    cleanUp();
    
    if ( _pExpr1 )
    {
	delete _pExpr1;
    }
    if ( _pExpr2 )
    {
	delete _pExpr2;
    }
    if ( _pExpr3 )
    {
	delete _pExpr3;
    }
    if (_pC)
    {	
	delete _pC;
    }
    if (_pNotPred)
    {	
	delete _pNotPred;
    }
    if (_pSelect)
    {
	delete _pSelect;
    }   
    if (_pMatcher)
    {
	delete _pMatcher;
    }
}

void CegoPredicate::setQueryManager(CegoQueryManager* pTabMng)
{
    if ( _pExpr1 )
    {
	_pExpr1->setQueryManager(pTabMng);
    }
    if ( _pExpr2 )
    {
	_pExpr2->setQueryManager(pTabMng);
    }
    if ( _pExpr3 )
    {
	_pExpr3->setQueryManager(pTabMng);
    }
    if (_pC)
    {	
	_pC->setQueryManager(pTabMng);
    }
    if (_pNotPred)
    {	
	_pNotPred->setQueryManager(pTabMng);
    }
    if (_pSelect)
    {
	_pSelect->setTableManager(pTabMng);	
    }
}

void CegoPredicate::setTabSetId(unsigned tabSetId)
{
    if ( _pExpr1 )
    {
	_pExpr1->setTabSetId(tabSetId);
    }
    if ( _pExpr2 )
    {
	_pExpr2->setTabSetId(tabSetId);
    }
    if ( _pExpr3 )
    {
	_pExpr3->setTabSetId(tabSetId);
    }
    if (_pC)
    {	
	_pC->setTabSetId(tabSetId);
    }
    if (_pNotPred)
    {	
	_pNotPred->setTabSetId(tabSetId);
    }
    if (_pSelect)
    {
	_pSelect->setTabSetId(tabSetId);
    }
}

void CegoPredicate::getPlanList(ListT<Element*>& planList)
{

    if (_pSelect)
    {
	planList.Insert( _pSelect->getPlan() );
    }
    if ( _pC )
    {
	_pC->getPlanList(planList);	
    }
    if (_pNotPred)
    {
	_pNotPred->getPlanList(planList);
    }
    if ( _pExpr1 )
    {
	_pExpr1->getPlanList(planList);
    }
    if ( _pExpr2 )
    {
	_pExpr2->getPlanList(planList);
    }
    if ( _pExpr3 )
    {
	_pExpr3->getPlanList(planList);
    }
}

CegoPredicate& CegoPredicate::operator = ( const CegoPredicate& p)
{
    _pExpr1 = p._pExpr1;
    _pExpr2 = p._pExpr2;
    _pExpr3 = p._pExpr3;
    _exprList = p._exprList;
    _pattern = p._pattern;
    _pMatcher = p._pMatcher;
    _comp = p._comp;
    _pSelect = p._pSelect;
    _pC = p._pC;
    _pNotPred = p._pNotPred;
    _mode = p._mode;
    _isChecked = p._isChecked;
    return (*this);
}

void CegoPredicate::liftCondition()
{
    if ( _mode == CegoPredicate::EXPRONLY  )
    {
	if ( _pExpr1->getType() == CegoExpr::TERM )
	{
	    if ( _pExpr1->getTerm()->getType() == CegoTerm::FACTOR )
	    {
		if ( _pExpr1->getTerm()->getFactor()->getType() == CegoFactor::CONDITION )
		{
		    
		    _pC = _pExpr1->getTerm()->getFactor()->grapCondition();
		    _mode = CegoPredicate::CONDITION;		    		    
		    delete _pExpr1;
		    _pExpr1 = 0;
		    
		    if ( _pC->Left() )
			_pC->Left()->liftCondition();
		    if ( _pC->Right() )
			_pC->Right()->liftCondition();
		    
		}
	    }
	}
    }
}

void CegoPredicate::analyzeSelect()
{
    if ( _pSelect )
	_pSelect->prepare();
    if ( _pC )
    {
	if ( _pC->Left() )
	    _pC->Left()->analyzeSelect();
	if ( _pC->Right() )
	    _pC->Right()->analyzeSelect();
    }
    if ( _pNotPred )
    {
	_pNotPred->analyzeSelect();
    }
}

CegoSelect* CegoPredicate::getSelectQuery()
{
    return _pSelect;
}

void CegoPredicate::getSelectQueryList(ListT<CegoSelect*>& queryList)
{   
    if ( _pSelect )
	queryList.Insert(_pSelect);

    if ( _pExpr1 )
    {
	_pExpr1->getSelectQueryList(queryList);
    }
    if ( _pExpr2 )
    {
	_pExpr2->getSelectQueryList(queryList);
    }
    if ( _pExpr3 )
    {
	_pExpr3->getSelectQueryList(queryList);
    }

    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	(*pExpr)->getSelectQueryList(queryList);
	pExpr = _exprList.Next();
    }   
    
    if ( _pC )
    {
	if ( _pC->Left() )
	    _pC->Left()->getSelectQueryList(queryList);
	if ( _pC->Right() )
	    _pC->Right()->getSelectQueryList(queryList);
    }
    if ( _pNotPred )
    {
	_pNotPred->getSelectQueryList(queryList);
    }
}

CegoCondition* CegoPredicate::getCondition()
{
    return _pC;
}

CegoPredicate* CegoPredicate::getNotPred()
{
    return _pNotPred;
}

CegoComparison CegoPredicate::getComparison()
{
    return _comp;
}

CegoPredicate::CompMode CegoPredicate::getMode()
{
    return _mode;
}

CegoExpr* CegoPredicate::getExpr1()
{
    return _pExpr1;
}

CegoExpr* CegoPredicate::getExpr2()
{
    return _pExpr2;
}

CegoExpr* CegoPredicate::getExpr3()
{
    return _pExpr3;
}

ListT<CegoExpr*>& CegoPredicate::getExprList()
{
    return _exprList;
}

void CegoPredicate::setChecked(bool val)
{
    _isChecked = val;
}

void CegoPredicate::clearAttrCache()
{
    if ( _pExpr1 )
    {
	_pExpr1->clearAttrCache();
    }
    if ( _pExpr2 )
    {
	_pExpr2->clearAttrCache();
    }
    if ( _pExpr3 )
    {
	_pExpr3->clearAttrCache();
    }

    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	(*pExpr)->clearAttrCache();
	pExpr = _exprList.Next();
    }   
    
    if ( _pC )
    {
	if ( _pC->Left() )
	    _pC->Left()->clearAttrCache();
	if ( _pC->Right() )
	    _pC->Right()->clearAttrCache();
    }
    if ( _pNotPred )
    {
	_pNotPred->clearAttrCache();
    }
}

void CegoPredicate::cleanUp()
{
    if ( _pExpr1 )
    {
	_pExpr1->cleanUp();
    }
    if ( _pExpr2 )
    {
	_pExpr2->cleanUp();
    }
    if ( _pExpr3 )
    {
	_pExpr3->cleanUp();
    }

    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	(*pExpr)->cleanUp();
	pExpr = _exprList.Next();
    }   
    
    if (_pNotPred)
    {	
	_pNotPred->cleanUp();
    }
    if (_pC)
    {
	_pC->cleanUp();
    }
    if (_pSelect)
    {
	_pSelect->cleanUp();
    }   
}

void CegoPredicate::setCheckedRec(bool val)
{
    _isChecked = val;
    if ( _pC )
    {
	_pC->Left()->setCheckedRec(val);
	if ( _pC->Right() )
	    _pC->Right()->setCheckedRec(val);       
    }
    if ( _pNotPred )
    {
	_pNotPred->setChecked(val);
    }
}

bool CegoPredicate::isChecked() const
{
    return _isChecked;
}

bool CegoPredicate::isCursorPred() const
{
    bool isPred = false;
    
    switch (_mode )
    {
    case CegoPredicate::CONDITION:
    {
	isPred = _pC->isCursorPred();
	break;
    }
    case CegoPredicate::NOTPRED:
    {
	isPred = _pNotPred->isCursorPred();
	break;
    }
    case CegoPredicate::EXPRCOMP:
    case CegoPredicate::BETWEEN:
    case CegoPredicate::EXPRONLY:
    case CegoPredicate::NULLCOMP:
    case CegoPredicate::NOTNULLCOMP:
    case CegoPredicate::IN:
    case CegoPredicate::ISLIKE:
    case CegoPredicate::ISNOTLIKE:
    case CegoPredicate::ISNCLIKE:
    case CegoPredicate::ISNOTNCLIKE:
    {
	isPred = true;
	break;
    }
    case CegoPredicate::EXISTSCOMP:
    case CegoPredicate::INSUB:
    case CegoPredicate::NOTINSUB:
    case CegoPredicate::NOTIN:
    {
	isPred = false;
	break;
    }
    }
    return isPred;
}

bool CegoPredicate::prioOnJoin() const
{
    if ( _mode == CegoPredicate::EXPRCOMP
	 && _comp == NOT_EQUAL )
	return false;
    if ( _mode == CegoPredicate::ISLIKE
	 ||  _mode == CegoPredicate::ISNOTLIKE
	 ||  _mode == CegoPredicate::ISNCLIKE 
	 ||  _mode == CegoPredicate::ISNOTNCLIKE )
	return false;
    if ( hasOrCond() )
	return false;
    return true;
}

bool CegoPredicate::hasOrCond() const
{
    if (_pC)
    {
	if ( _pC->getCondType() == CegoCondition::OR )
	    return true;
	else if ( _pC->getCondType() == CegoCondition::AND )
	    return _pC->Left()->hasOrCond() || _pC->Right()->hasOrCond();       
	else if ( _pC->getCondType() == CegoCondition::PRED )
	    return _pC->Left()->hasOrCond();
    }
    return false;
}

const Chain& CegoPredicate::getPattern() const
{
    return _pattern;
}

bool CegoPredicate::match(const CegoFieldValue& val)
{    
    // for performance reasons, we build up matcher on demand
    // since it might occcur, that the predicate is evaluated via CegoDistCursor via CegoAttrCond
    if ( _pMatcher == 0 )
    {
	
	Chain regexPattern;
	if ( _mode == CegoPredicate::ISLIKE || _mode == CegoPredicate::ISNOTLIKE )
	    regexPattern = CegoQueryHelper::sql2Regex(_pattern);
	else
	    regexPattern = CegoQueryHelper::sql2Regex(_pattern.toLower());
	
	_pMatcher = new Matcher(regexPattern);	
	_pMatcher->prepare();
    }
    
    if ( _mode == CegoPredicate::ISLIKE || _mode == CegoPredicate::ISNOTLIKE )
	return _pMatcher->match(val.valAsChain());
    else
	return _pMatcher->match(val.valAsChain().toLower());
	
}

void CegoPredicate::encode(char *buf, CegoProcBlock* pBlock)
{
    char* pP = (char*)buf;
    
    memcpy( pP, &_mode, sizeof(CegoPredicate::CompMode));
    pP = pP + sizeof(CegoPredicate::CompMode);

    switch (_mode )
    {
    case CegoPredicate::CONDITION:
    {
	_pC->encode(pP, pBlock);
	pP = pP + _pC->getEncodingLength(pBlock);
	break;
    }
    case CegoPredicate::NOTPRED:
    {
	_pNotPred->encode(pP, pBlock);
	pP = pP + _pNotPred->getEncodingLength(pBlock);
	break;
    }
    case CegoPredicate::EXPRCOMP:
    {	
	memcpy( pP, &_comp, sizeof(CegoComparison));
	pP = pP + sizeof(CegoComparison);
	
	_pExpr1->encode(pP, pBlock);
	pP = pP + _pExpr1->getEncodingLength(pBlock);

	_pExpr2->encode(pP, pBlock);
	pP = pP + _pExpr2->getEncodingLength(pBlock);

	break;
    }
    case CegoPredicate::BETWEEN:
    {	
	_pExpr1->encode(pP, pBlock);
	pP = pP + _pExpr1->getEncodingLength(pBlock);
	
	_pExpr2->encode(pP, pBlock);
	pP = pP + _pExpr2->getEncodingLength(pBlock);

	_pExpr3->encode(pP, pBlock);
	pP = pP + _pExpr3->getEncodingLength(pBlock);

	break;
    }
    case CegoPredicate::EXPRONLY:
    case CegoPredicate::NULLCOMP:
    case CegoPredicate::NOTNULLCOMP:
    {
	_pExpr1->encode(pP, pBlock);
	pP = pP + _pExpr1->getEncodingLength(pBlock);
	break;
    }
    case CegoPredicate::EXISTSCOMP:
    {
	_pSelect->encode(pP, pBlock);
	pP = pP + _pSelect->getEncodingLength(pBlock);
	break;
    }
    case CegoPredicate::INSUB:
    case CegoPredicate::NOTINSUB:
    {	
	_pExpr1->encode(pP, pBlock);
	pP = pP + _pExpr1->getEncodingLength(pBlock);
	_pSelect->encode(pP, pBlock);
	pP = pP + _pSelect->getEncodingLength(pBlock);
	break;
    }
    case CegoPredicate::IN:
    case CegoPredicate::NOTIN:
    {	
	_pExpr1->encode(pP, pBlock);
	pP = pP + _pExpr1->getEncodingLength(pBlock);

	unsigned num = _exprList.Size();
	memcpy( pP, &num, sizeof(unsigned));
	pP = pP + sizeof(unsigned);
      
	CegoExpr** pExpr = _exprList.First();
	while ( pExpr )
	{
	    (*pExpr)->encode(pP, pBlock);
	    pP = pP + (*pExpr)->getEncodingLength(pBlock);
	    pExpr = _exprList.Next();
	}   

	break;
    }
    case CegoPredicate::ISLIKE:
    case CegoPredicate::ISNOTLIKE:
    case CegoPredicate::ISNCLIKE:
    case CegoPredicate::ISNOTNCLIKE:
    {
	_pExpr1->encode(pP, pBlock);
	pP = pP + _pExpr1->getEncodingLength(pBlock);

	char len = _pattern.length();

	memcpy( pP, &len, sizeof(char));
	pP = pP + sizeof(char);

	memcpy( pP, (char*)_pattern, len);
	pP = pP + len;

	break;
    }
    }
}

void CegoPredicate::decode(char *buf)
{
    char* pP = (char*)buf;

    memcpy( &_mode, pP, sizeof(CegoPredicate::CompMode));
    pP = pP + sizeof(CegoPredicate::CompMode);
    
    // init condition and notpred as zero
    _pC = 0;
    _pNotPred = 0;
    _pSelect = 0;
    _pExpr1=0;
    _pExpr2=0;
    _pExpr3=0;

    switch (_mode )
    {
    case CegoPredicate::CONDITION:
    {
	_pC = new CegoCondition(pP);
	pP = pP + _pC->getEncodingLength();
	break;
    }
    case CegoPredicate::NOTPRED:
    {
	_pNotPred = new CegoPredicate(pP);
	pP = pP + _pNotPred->getEncodingLength();
	break;
    }
    case CegoPredicate::EXPRCOMP:
    {	
	memcpy( &_comp, pP, sizeof(CegoComparison));
	pP = pP + sizeof(CegoComparison);

	_pExpr1 = new CegoExpr(pP);
	pP = pP + _pExpr1->getEncodingLength();

	_pExpr2 = new CegoExpr(pP);
	pP = pP + _pExpr2->getEncodingLength();
	break;
    }
    case CegoPredicate::BETWEEN:
    {	
	_pExpr1 = new CegoExpr(pP);
	pP = pP + _pExpr1->getEncodingLength();

	_pExpr2 = new CegoExpr(pP);
	pP = pP + _pExpr2->getEncodingLength();

	_pExpr3 = new CegoExpr(pP);
	pP = pP + _pExpr3->getEncodingLength();
	break;
    }
    case CegoPredicate::EXPRONLY:
    case CegoPredicate::NULLCOMP:
    case CegoPredicate::NOTNULLCOMP:
    {
	_pExpr1 = new CegoExpr(pP);
	pP = pP + _pExpr1->getEncodingLength();
	break;
    }
    case CegoPredicate::EXISTSCOMP:
    {
	_pSelect = new CegoSelect(pP);
	pP = pP + _pSelect->getEncodingLength();
	break;
    }
    case CegoPredicate::INSUB:
    case CegoPredicate::NOTINSUB:
    {
	_pExpr1 = new CegoExpr(pP);
	pP = pP + _pExpr1->getEncodingLength();
	_pSelect = new CegoSelect(pP);
	pP = pP + _pSelect->getEncodingLength();	
	break;
    }
    case CegoPredicate::IN:
    case CegoPredicate::NOTIN:
    {	
	_pExpr1 = new CegoExpr(pP);
	pP = pP + _pExpr1->getEncodingLength();

	unsigned num;
	memcpy( &num, pP, sizeof(unsigned));
	pP = pP + sizeof(unsigned);

	for ( unsigned i=0; i<num; i++ )
	{
	    CegoExpr *pExpr = new CegoExpr(pP);
	    _exprList.Insert(pExpr);
	    pP = pP + pExpr->getEncodingLength();
	}
	break;
    }
    case CegoPredicate::ISLIKE:
    case CegoPredicate::ISNOTLIKE:
    case CegoPredicate::ISNCLIKE:
    case CegoPredicate::ISNOTNCLIKE:
    {
	_pExpr1 = new CegoExpr(pP);
	pP = pP + _pExpr1->getEncodingLength();
	
	char len;
	memcpy( &len, pP, sizeof(char));
	pP = pP + sizeof(char);

	_pattern = Chain(pP, len);
	pP = pP + len;
	break;
    }
    }
}

unsigned CegoPredicate::getEncodingLength(CegoProcBlock* pBlock) const
{
    unsigned len = 0;
    
    len += sizeof(CegoPredicate::CompMode);
    
    switch (_mode )
    {
    case CegoPredicate::CONDITION:
    {
	len += _pC->getEncodingLength(pBlock);
	break;
    }
    case CegoPredicate::NOTPRED:
    {
	len += _pNotPred->getEncodingLength(pBlock);
	break;
    }
    case CegoPredicate::EXPRCOMP:
    {
	len += sizeof(CegoComparison);
	len += _pExpr1->getEncodingLength(pBlock);
	len += _pExpr2->getEncodingLength(pBlock);
	break;
    }
    case CegoPredicate::BETWEEN:
    {
	len += _pExpr1->getEncodingLength(pBlock);
	len += _pExpr2->getEncodingLength(pBlock);
	len += _pExpr3->getEncodingLength(pBlock);
	break;
    }
    case CegoPredicate::ISLIKE:
    case CegoPredicate::ISNOTLIKE:
    case CegoPredicate::ISNCLIKE:
    case CegoPredicate::ISNOTNCLIKE:
    {
	len += _pExpr1->getEncodingLength(pBlock);
	len += 1; // sizeof pattern
	len += _pattern.length();
	break;
    }
    case CegoPredicate::EXPRONLY:
    case CegoPredicate::NULLCOMP:
    case CegoPredicate::NOTNULLCOMP:
    {
	len += _pExpr1->getEncodingLength(pBlock);
	break;
    }
    case CegoPredicate::EXISTSCOMP:
    {
	len += _pSelect->getEncodingLength(pBlock);
	break;
    }
    case CegoPredicate::INSUB:
    case CegoPredicate::NOTINSUB:
    {
	len += _pExpr1->getEncodingLength(pBlock);
	len += _pSelect->getEncodingLength(pBlock);
	break;
    }
    case CegoPredicate::IN:
    case CegoPredicate::NOTIN:
    {
	len += _pExpr1->getEncodingLength(pBlock);
	len += sizeof(unsigned);

	CegoExpr** pExpr = _exprList.First();
	while ( pExpr )
	{
	    len += (*pExpr)->getEncodingLength(pBlock);	    
	    pExpr = _exprList.Next();
	}
	break;
    }
    }    
    return len;
}

SetT<Chain> CegoPredicate::getTableRefSet() const
{
    SetT<Chain> tableRefSet;
    ListT<CegoAttrDesc*> adList = getAttrRefList();
    CegoAttrDesc **pAD = adList.First();
    while ( pAD )
    {
	tableRefSet.Insert((*pAD)->getTableName());
	pAD = adList.Next();
    }
    return tableRefSet;
}

ListT<CegoAttrDesc*> CegoPredicate::getAttrRefList() const
{
    ListT<CegoAttrDesc*> al;

    switch (_mode )
    {
    case CegoPredicate::CONDITION:
    {
	al = _pC->getAttrRefList();
	break;
    }
    case CegoPredicate::NOTPRED:
    {
	al = _pNotPred->getAttrRefList();
	break;
    }
    case CegoPredicate::EXPRCOMP:
    {
	al = _pExpr1->getAttrRefList();
	al += _pExpr2->getAttrRefList();
	break;
    }
    case CegoPredicate::BETWEEN:
    {
	al = _pExpr1->getAttrRefList();
	al += _pExpr2->getAttrRefList();
	al += _pExpr3->getAttrRefList();
	break;
    }
    case CegoPredicate::ISLIKE:
    case CegoPredicate::ISNOTLIKE:
    case CegoPredicate::ISNCLIKE:
    case CegoPredicate::ISNOTNCLIKE:
    {
	al += _pExpr1->getAttrRefList();
	break;
    }
    case CegoPredicate::EXPRONLY:
    case CegoPredicate::NULLCOMP:
    case CegoPredicate::NOTNULLCOMP:
    {
	al += _pExpr1->getAttrRefList();
	break;
    }
    case CegoPredicate::INSUB:
    case CegoPredicate::NOTINSUB:
    {
	al = _pExpr1->getAttrRefList();
	al += _pSelect->getAttrRefList();
	break;
    }
    case CegoPredicate::IN:
    case CegoPredicate::NOTIN:
    {
	al = _pExpr1->getAttrRefList();	
	CegoExpr** pExpr = _exprList.First();
	while ( pExpr )
	{
	    al += (*pExpr)->getAttrRefList();	    
	    pExpr = _exprList.Next();
	}
	break;
    }
    case CegoPredicate::EXISTSCOMP:
    {
	al = _pSelect->getAttrRefList();
	break;
    }    
    }
    return al; 
}

unsigned CegoPredicate::evalReferences(CegoContentObject *pCO, const ListT<CegoField>& fl)
{
    unsigned refCount = 0;
    
    switch (_mode )
    {
    case CegoPredicate::CONDITION:
    {
	refCount += _pC->evalReferences(pCO, fl);
	break;
    }
    case CegoPredicate::NOTPRED:
    {
	refCount += _pNotPred->evalReferences(pCO, fl);
	break;
    }
    case CegoPredicate::EXPRCOMP:
    {
 	refCount += _pExpr1->evalReferences(pCO, fl);
	refCount += _pExpr2->evalReferences(pCO, fl);
	break;
    }
    case CegoPredicate::BETWEEN:
    {
	refCount += _pExpr1->evalReferences(pCO, fl);
	refCount += _pExpr2->evalReferences(pCO, fl);
	refCount += _pExpr3->evalReferences(pCO, fl);
	break;
    }
    case CegoPredicate::ISLIKE:
    case CegoPredicate::ISNOTLIKE:
    case CegoPredicate::ISNCLIKE:
    case CegoPredicate::ISNOTNCLIKE:
    {
	refCount += _pExpr1->evalReferences(pCO, fl);
	break;
    }
    case CegoPredicate::EXPRONLY:
    case CegoPredicate::NULLCOMP:
    case CegoPredicate::NOTNULLCOMP:
    {
	refCount += _pExpr1->evalReferences(pCO, fl);
	break;
    }
    case CegoPredicate::INSUB:
    case CegoPredicate::NOTINSUB:
    {
	refCount += _pExpr1->evalReferences(pCO, fl);
	_pSelect->prepare();
	refCount += _pSelect->evalExtTableReferences(pCO, fl);
	break;
    }
    case CegoPredicate::IN:
    case CegoPredicate::NOTIN:
    {
	refCount += _pExpr1->evalReferences(pCO, fl);

	CegoExpr** pExpr = _exprList.First();
	while ( pExpr )
	{
	    refCount += (*pExpr)->evalReferences(pCO, fl);
	    pExpr = _exprList.Next();
	}
	break;
    }
    case CegoPredicate::EXISTSCOMP:
    {
	_pSelect->prepare();
	refCount += _pSelect->evalExtTableReferences(pCO, fl);
	break;
    }    
    }

    return refCount;
}

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

    if ( _pExpr1 )
    {
	aggList = aggList + _pExpr1->getAggregationList();
    }

    if ( _pExpr2 )
    {
	aggList = aggList + _pExpr2->getAggregationList();
    }

    if ( _pExpr3 )
    {
	aggList = aggList + _pExpr3->getAggregationList();
    }

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

    if (_pC)
    {	
	aggList = aggList + _pC->getAggregationList();
    }
    
    if (_pNotPred)
    {
	aggList = aggList + _pNotPred->getAggregationList();
    }
    
    return aggList;
}

void CegoPredicate::getFieldList(ListT<CegoField>& fl, ListT<CegoField>** pFLA) const
{    
    switch (_mode )
    {
    case CegoPredicate::CONDITION:
    {
	_pC->getFieldList(fl, pFLA);
	break;
    }
    case CegoPredicate::NOTPRED:
    {
	_pNotPred->getFieldList(fl, pFLA);
	break;
    }
    case CegoPredicate::EXPRCOMP:
    {
	_pExpr1->getFieldList(fl, pFLA);
	_pExpr2->getFieldList(fl, pFLA);
	break;
    }
    case CegoPredicate::BETWEEN:
    {
	_pExpr1->getFieldList(fl, pFLA);
	_pExpr2->getFieldList(fl, pFLA);
	_pExpr3->getFieldList(fl, pFLA);
	break;
    }
    case CegoPredicate::ISLIKE:
    case CegoPredicate::ISNOTLIKE:
    case CegoPredicate::ISNCLIKE:
    case CegoPredicate::ISNOTNCLIKE:
    {
	_pExpr1->getFieldList(fl, pFLA);
	break;
    }
    case CegoPredicate::INSUB:
    case CegoPredicate::NOTINSUB:
    {
	_pExpr1->getFieldList(fl, pFLA);
	_pSelect->getFieldList(fl, pFLA);
	break;
    }
    case CegoPredicate::IN:
    case CegoPredicate::NOTIN:
    {
	_pExpr1->getFieldList(fl, pFLA);

	CegoExpr** pExpr = _exprList.First();
	while ( pExpr )
	{
	    (*pExpr)->getFieldList(fl, pFLA);
	    pExpr = _exprList.Next();
	}
	break;
    }
    case CegoPredicate::EXISTSCOMP:
    {
	_pSelect->getFieldList(fl, pFLA);
	break;
    }
    case CegoPredicate::EXPRONLY:
    case CegoPredicate::NULLCOMP:
    case CegoPredicate::NOTNULLCOMP:
    {
	_pExpr1->getFieldList(fl, pFLA);
	break;
    }
    }
}
    
bool CegoPredicate::eval(ListT<CegoField>** pParentJoinBuf,
			     unsigned parentJoinBufPos,
			     ListT<CegoField>** pJoinBuf,
			     unsigned pos,
			     CegoProcBlock *pBlock)
{
    
    if ( _pC )
    {
	switch ( _pC->getCondType() )
	{
	case CegoCondition::AND:
	    return ( _pC->Left()->eval(pParentJoinBuf, 
				   parentJoinBufPos,
				   pJoinBuf,
				   pos,
				   pBlock)
		     && _pC->Right()->eval(pParentJoinBuf,
				      parentJoinBufPos,
				      pJoinBuf,
				      pos,
				      pBlock));
	case CegoCondition::OR: 
	    return ( _pC->Left()->eval(pParentJoinBuf,
				       parentJoinBufPos,
				       pJoinBuf,
				       pos,
				       pBlock) 
		     || _pC->Right()->eval(pParentJoinBuf,
					   parentJoinBufPos,
					   pJoinBuf,
					   pos,
					   pBlock));
	case CegoCondition::PRED:
	    
	    return  _pC->Left()->eval(pParentJoinBuf,
				      parentJoinBufPos,
				      pJoinBuf,
				      pos,
				      pBlock);
	}
    } 
    else 
    {
	if ( _mode == CegoPredicate::NOTPRED )
	{
	    bool np = _pNotPred->eval(pParentJoinBuf,
				    parentJoinBufPos,
				    pJoinBuf,
				    pos,
				    pBlock);
	    if ( np )
	    {
		return false;
	    }
	    return true;
	}
	else if ( _mode == CegoPredicate::CONDITION )
	{
	    // should not occur, since condition case is already handled above
	}
	else
	{
	    // merge join buf and parent join buf
	    
	    ListT<CegoField>** flArray = 0;
	    ListT<CegoField>* flStaticArray[TABMNG_MAXJOINLEVEL];

	    if ( pParentJoinBuf )
	    {
		flArray = flStaticArray;
		
		unsigned flpos=0;

		// first we take join buf with high priority ( first match on join buf )
		
		unsigned i=pos;
		while ( pJoinBuf[i] )
		{
		    if ( flpos > TABMNG_MAXJOINLEVEL )
		    {
			Chain msg = Chain("Join buffer exceeded");
			throw Exception(EXLOC, msg);
		    }			

		    flArray[flpos] = pJoinBuf[i];
		    i++;
		    flpos++;
		}

                // now we take parent join buf we a lower priority
		
		i=parentJoinBufPos;
		while ( pParentJoinBuf[i] )
		{
		    if ( flpos > TABMNG_MAXJOINLEVEL )
		    {
			Chain msg = Chain("Join buffer exceeded");
			throw Exception(EXLOC, msg);
		    }			
			    
		    flArray[flpos] = pParentJoinBuf[i];
		    i++;
		    flpos++;
		}

		
		// terminate array
		flArray[flpos]=0;
	    }
	    else if ( pJoinBuf )
	    {
		flArray = pJoinBuf + pos;
	    }

	    // print flarray here for debugging

	    /*
	    cout << "### flArray start ###" << endl;
	    CegoField *pF = 0;	
	    int flaPos=0;
	    while ( flArray[flaPos] )
	    {
		CegoField *pF = flArray[flaPos]->First();

		while ( pF )
		{
		    cout << "Attr = " << pF->getTableAlias()  << "/" <<  pF->getTableName()
			 << "/" << pF->getAttrName() << "="  << pF->getValue().valAsChain() << endl;
		    pF = flArray[flaPos]->Next();
		}
		flaPos++;
	    }
	    cout << "### flArray end ###" << endl;
	    */
	    
	    bool retVal = false;
	    
	    switch ( _mode )
	    {	

	    case CegoPredicate::EXPRCOMP:
	    {		
		retVal = evalFields(_comp,
				    _pExpr1->evalFieldValue(flArray, pBlock),
				    _pExpr2->evalFieldValue(flArray, pBlock));
		break;
	    }    
	    case CegoPredicate::BETWEEN:
	    {
		retVal = evalBetween(_pExpr1->evalFieldValue(flArray, pBlock),
				     _pExpr2->evalFieldValue(flArray, pBlock),
				     _pExpr3->evalFieldValue(flArray, pBlock));
		
		break;
	    }    		
	    case CegoPredicate::NULLCOMP:
	    {		
		if ( _pExpr1->evalFieldValue(flArray, pBlock).isNull() )
		{
		    retVal = true;
		}
		else
		{
		    retVal = false;
		}
		break;
	    }
	    case CegoPredicate::NOTNULLCOMP:
	    {	
		if ( _pExpr1->evalFieldValue(flArray, pBlock).isNull() )
		{
		    retVal = false;
		}
		else
		{
		    retVal = true;
		}		
		break;
	    }
	    case CegoPredicate::EXPRONLY:
	    {		
		_exprOnlyVal = _pExpr1->evalFieldValue(flArray, pBlock);
		retVal = _exprOnlyVal.asBool();
		break;
	    }
	    case CegoPredicate::EXISTSCOMP:
	    {		
		_pSelect->reset();		
		if ( flArray )
		{
		    /*
		    cout << "Setting parent .." << endl;

		    
		    cout << "### flArray start ###" << endl;
		    CegoField *pF = 0;	
		    int flaPos=0;
		    while ( flArray[flaPos] )
		    {
			CegoField *pF = flArray[flaPos]->First();
			
			while ( pF )
			{
			    cout << "Attr = " << pF->getTableAlias()  << "/" <<  pF->getTableName()
				 << "/" << pF->getAttrName() << "="  << pF->getValue().valAsChain() << endl;
			    pF = flArray[flaPos]->Next();
			}
			flaPos++;
		    }
		    cout << "### flArray end ###" << endl;
		    */

		    _pSelect->setParentJoinBuf(flArray);		    
		}
		_pSelect->setProcBlock(pBlock);

		_pSelect->prepare();
		
		ListT<CegoField> fl;

		// cout << "Select = " << _pSelect->toChain(0) << endl;
		
		if ( _pSelect->nextTuple(fl) )
		{
		    retVal= true;
		}
		else
		{
		    retVal = false;
		}

		if ( flArray )
		{		    
		    flArray=0;
		}
		_pSelect->setProcBlock(0);		
		_pSelect->setParentJoinBuf();
		_pSelect->reset();
		break;
	    }
	    case CegoPredicate::ISLIKE:
	    case CegoPredicate::ISNOTLIKE:
	    case CegoPredicate::ISNCLIKE:
	    case CegoPredicate::ISNOTNCLIKE:
	    {
		if ( _mode == CegoPredicate::ISLIKE || _mode == CegoPredicate::ISNCLIKE)
		    retVal = match(_pExpr1->evalFieldValue(flArray, pBlock));
		else
		    retVal =  ! match(_pExpr1->evalFieldValue(flArray, pBlock));
		break;
	    }
	    case CegoPredicate::IN:
	    case CegoPredicate::NOTIN:
	    {
		CegoExpr **pExpr = _exprList.First();

		bool matchFound = false;
		while ( pExpr && matchFound == false )
		{		    
		    if ( _pExpr1->evalFieldValue(flArray, pBlock) == (*pExpr)->evalFieldValue(flArray, pBlock) )
		    {
			matchFound = true;
		    }		    
		    pExpr = _exprList.Next();
		}

		if ( _mode == CegoPredicate::IN )
		    retVal = matchFound;
		else
		    retVal = ! matchFound;				
		break;           	
	    }
	    case CegoPredicate::INSUB:
	    case CegoPredicate::NOTINSUB:
	    {
		_pSelect->reset();

		if ( flArray )
		{		    
		    _pSelect->setParentJoinBuf(flArray);
		}
		_pSelect->setProcBlock(pBlock);

		_pSelect->prepare();
		
		ListT<CegoField> fl;
				
		if ( _mode == CegoPredicate::INSUB )
		{
		    retVal = false;
		    while ( _pSelect->nextTuple(fl) && retVal == false )
		    {
			CegoField *pSF = fl.First();

			if ( (CegoFieldValue)pSF->getValue() == (CegoFieldValue)_pExpr1->evalFieldValue(flArray, pBlock) )
			    retVal = true;
		    }
		}
		else
		{ 
		    retVal = true;
		    while ( _pSelect->nextTuple(fl) && retVal == true )
		    {
			CegoField *pSF = fl.First();
			if ( (CegoFieldValue)pSF->getValue() == (CegoFieldValue)_pExpr1->evalFieldValue(flArray, pBlock) )
			    retVal = false;
		    }
		}
		
		// in case of caching, we have to read to the end to fill up cache
		if ( _pSelect->isCacheEnabled() == true && _pSelect->isCached() == false )
		{
		    while ( _pSelect->nextTuple(fl));
		}
		_pSelect->setProcBlock(0);
		_pSelect->setParentJoinBuf();
		_pSelect->reset();
		
		break;    
	    }
	    case CegoPredicate::NOTPRED:
	    {
		// already handled
		break;
	    }
	    case CegoPredicate::CONDITION:
		// already handled
		break;
	    }

	    // we avoid cleanUp here for performance reasons
	    // still not clear, if really needed ..
	    // cleanUp();
	    
	    return retVal;
	}
    }
    return false;
}

CegoField CegoPredicate::evalField(const ListT<CegoField>& fl, bool graceful) const
{
    CegoField f;
    
    switch (_mode )
    {
    case CegoPredicate::CONDITION:
    {
	f = _pC->evalField(fl, graceful);
	break;
    }
    case CegoPredicate::NOTPRED:
    case CegoPredicate::EXPRCOMP:
    case CegoPredicate::BETWEEN:
    case CegoPredicate::ISLIKE:
    case CegoPredicate::ISNOTLIKE:
    case CegoPredicate::ISNCLIKE:
    case CegoPredicate::ISNOTNCLIKE:
    case CegoPredicate::INSUB:
    case CegoPredicate::NOTINSUB:
    case CegoPredicate::IN:
    case CegoPredicate::NOTIN:
    case CegoPredicate::EXISTSCOMP:
    case CegoPredicate::NULLCOMP:
    case CegoPredicate::NOTNULLCOMP:
    {
	f = CegoField( Chain("PRED"), Chain("PRED"), Chain("PRED"), BOOL_TYPE, sizeof(char));
	break;
    }
    case CegoPredicate::EXPRONLY:
    {
	f = _pExpr1->evalField(fl, graceful);
	break;
    }
    }
    return f;
}
    
CegoFieldValue CegoPredicate::getExprOnlyValue() const
{
    return _exprOnlyVal;
}

CegoPredicate* CegoPredicate::map(const Chain& viewAlias, ListT<CegoExpr*> exprList) const
{
   
    switch (_mode )
    {
    case CegoPredicate::CONDITION:
    {
	CegoPredicate* pLeft = 0;
	CegoPredicate* pRight = 0;

	bool mapOk=true;
	if ( _pC->Left() )
	{
	    pLeft = _pC->Left()->map(viewAlias, exprList);
	    if ( pLeft == 0 )
	    {
		mapOk=false;
	    }
	}
	if ( _pC->Right() )
	{
	    pRight = _pC->Right()->map(viewAlias, exprList);
	    if ( pRight == 0 )
	    {
		mapOk = false;
	    }
	}
	if ( mapOk )
	{
	    CegoCondition* pC =  new CegoCondition(_pC->getCondType(), pLeft, pRight);
	    return new CegoPredicate(pC);
	}
	else
	{
	    if ( pLeft )
		delete pLeft;
	    if ( pRight )
		delete pRight;
	}
	break;
    }
    case CegoPredicate::NOTPRED:
    {
	CegoPredicate* pMap = _pNotPred->map(viewAlias, exprList);
	if ( pMap )
	    return new CegoPredicate(pMap);
	break;
    }
    case CegoPredicate::EXPRCOMP:
    {
	bool mapOk=true;
	CegoExpr* pExpr1=0;
	if ( _pExpr1 )
	{
	    pExpr1 = mapExpr(viewAlias, exprList, _pExpr1);
	    if ( pExpr1 == 0 )
		mapOk=false;
	}
	CegoExpr* pExpr2=0;
	if ( _pExpr2 )
	{
	    pExpr2 = mapExpr(viewAlias, exprList, _pExpr2);
	    if ( pExpr2 == 0 )
		mapOk=false;
	}
	if ( mapOk )
	{
	    return new CegoPredicate(pExpr1, pExpr2, _comp);
	}
	else
	{
	    if ( pExpr1 )
		delete pExpr1;
	    if ( pExpr2 )
		delete pExpr2;
	}	
	break;
    }
    case CegoPredicate::BETWEEN:
    {
	bool mapOk=true;
	CegoExpr* pExpr1=0;
	if ( _pExpr1 )
	{
	    pExpr1 = mapExpr(viewAlias, exprList, _pExpr1);
	    if ( pExpr1 == 0 )
		mapOk=false;
	}
	CegoExpr* pExpr2=0;
	if ( _pExpr2 )
	{
	    pExpr2 = mapExpr(viewAlias, exprList, _pExpr2);
	    if ( pExpr2 == 0 )
		mapOk=false;
	}
	CegoExpr* pExpr3=0;
	if ( _pExpr3 )
	{
	    pExpr3 = mapExpr(viewAlias, exprList, _pExpr3);
	    if ( pExpr3 == 0 )
		mapOk=false;
	}

	if ( mapOk )
	{
	    return new CegoPredicate(pExpr1, pExpr2, pExpr3);
	}
	else
	{
	    if ( pExpr1 )
		delete pExpr1;
	    if ( pExpr2 )
		delete pExpr2;
	    if ( pExpr3 )
		delete pExpr3;	    
	}
	break;
    }
    case CegoPredicate::ISLIKE:
    case CegoPredicate::ISNOTLIKE:
    case CegoPredicate::ISNCLIKE:
    case CegoPredicate::ISNOTNCLIKE:
    {
	CegoExpr* pExpr1=0;
	if ( _pExpr1 )
	{
	    pExpr1 = mapExpr(viewAlias, exprList, _pExpr1);
	}

	if ( pExpr1 )
	{
	    if ( _mode == CegoPredicate::ISLIKE )
		return new CegoPredicate(pExpr1, _pattern, false, true);
	    if ( _mode == CegoPredicate::ISNOTLIKE )
		return new CegoPredicate(pExpr1, _pattern, true, true);
	    if ( _mode == CegoPredicate::ISNCLIKE )
		return new CegoPredicate(pExpr1, _pattern, false, false);
	    if ( _mode == CegoPredicate::ISNOTNCLIKE )
		return new CegoPredicate(pExpr1, _pattern, true, false);	    	    
	}
    }
    case CegoPredicate::NULLCOMP:
    case CegoPredicate::NOTNULLCOMP:
    {
	CegoExpr* pExpr1=0;
	if ( _pExpr1 )
	{
	    pExpr1 = mapExpr(viewAlias, exprList, _pExpr1);
	}
	if ( _mode == CegoPredicate::NULLCOMP )
	    return new CegoPredicate(pExpr1, true);
	if ( _mode == CegoPredicate::NOTNULLCOMP )
	    return new CegoPredicate(pExpr1, false);	
	break;
    }
    case CegoPredicate::IN:
    case CegoPredicate::NOTIN:
    {

	bool isValid=true;
	
	CegoExpr* pExpr1=0;
	ListT<CegoExpr*> exprList;
	
	if ( _pExpr1 )
	{
	    pExpr1 = mapExpr(viewAlias, exprList, _pExpr1);
	}
	
	if ( pExpr1 )
	{	  
	    CegoExpr** pInExpr = _exprList.First();
	    while ( pInExpr && isValid )
	    {
		CegoExpr* pExpr = mapExpr(viewAlias, exprList,  *pInExpr);
		if ( pExpr )
		    exprList.Insert(pExpr);
		else
		    isValid = false;
		pInExpr = _exprList.Next();
	    }
	}
	if ( pExpr1 && isValid )
	{
	    if ( _mode == CegoPredicate::IN )
		return new CegoPredicate(pExpr1, exprList, false);
	    if ( _mode == CegoPredicate::NOTIN )
		return new CegoPredicate(pExpr1, exprList, true);
	}
	else
	{
	    if ( pExpr1 )
		delete pExpr1;
	    CegoExpr** pInExpr = exprList.First();
	    while ( pInExpr  )
	    {
		delete *pInExpr;
		pInExpr = exprList.Next();
	    }	    
	}
	break;
    }
	
    case CegoPredicate::INSUB:
    case CegoPredicate::NOTINSUB:
    case CegoPredicate::EXISTSCOMP:
    {
	// not handled
	break;
    }
    case CegoPredicate::EXPRONLY:
    {
	CegoExpr* pExpr1=0;
	if ( _pExpr1 )
	{
	    pExpr1 = mapExpr(viewAlias, exprList, _pExpr1);
	}
		
	if ( pExpr1 )
	{
	    return new CegoPredicate(pExpr1);
	}
	break;
    }
    }

    return 0;
}

CegoPredicate* CegoPredicate::getReduced(const Chain& tableAlias) const
{
    ListT<Chain> aliasList;
    aliasList.Insert(tableAlias);
    return getReduced(aliasList);
}

CegoPredicate* CegoPredicate::getReduced(const ListT<Chain>& aliasList) const
{    
    switch (_mode )
    {
    case CegoPredicate::CONDITION:
    {
	CegoPredicate* pLeft = 0;
	CegoPredicate* pRight = 0;

	
	if ( _pC->Left() )
	{
	    pLeft = _pC->Left()->getReduced(aliasList);
	}
	if ( _pC->Right() )
	{
	    pRight = _pC->Right()->getReduced(aliasList);
	}

	if ( _pC->getCondType() == CegoCondition::PRED && pLeft )
	{
	    CegoCondition* pC =  new CegoCondition(_pC->getCondType(), pLeft, 0);
	    return new CegoPredicate(pC);	    
	}
	if ( pRight && pLeft )
	{
	    CegoCondition* pC =  new CegoCondition(_pC->getCondType(), pLeft, pRight);
	    return new CegoPredicate(pC);
	}
	if ( pRight && _pC->getCondType() == CegoCondition::AND)
	{
	    return pRight;
	}
	if ( pLeft && _pC->getCondType() == CegoCondition::AND)
	{
	    return pLeft;
	}
	
	if ( pRight )
	    delete pRight;
	if ( pLeft )
	    delete pLeft;
	
	break;
    }
    case CegoPredicate::NOTPRED:
    {
	CegoPredicate* pReduced = _pNotPred->getReduced(aliasList);
	return pReduced;
    }
    case CegoPredicate::EXPRCOMP:
    {
	CegoExpr* pExpr1=0;
	CegoExpr* pExpr2=0;
	if ( _pExpr1 )
	{
	    pExpr1 = reduceExpr(aliasList, _pExpr1);
	}
	if ( _pExpr2 )
	{
	    pExpr2 = reduceExpr(aliasList, _pExpr2);
	}
	if ( pExpr1 && pExpr2 )
	{
	    return new CegoPredicate(pExpr1, pExpr2, _comp);
	}
	else
	{
	    if ( pExpr1 )
		delete pExpr1;
	    if ( pExpr2 )
		delete pExpr2;
	}	
	break;
    }
    case CegoPredicate::BETWEEN:
    {
	CegoExpr* pExpr1=0;
	CegoExpr* pExpr2=0;
	CegoExpr* pExpr3=0;
	if ( _pExpr1 )
	{
	    pExpr1 = reduceExpr(aliasList, _pExpr1);
	}
	if ( _pExpr2 )
	{
	    pExpr2 = reduceExpr(aliasList, _pExpr2);
	}
	if ( _pExpr3 )
	{
	    pExpr3 = reduceExpr(aliasList, _pExpr3);
	}

	if ( pExpr1 && pExpr2 && pExpr3 )
	{
	    return new CegoPredicate(pExpr1, pExpr2, pExpr3);
	}
	else
	{
	    if ( pExpr1 )
		delete pExpr1;
	    if ( pExpr2 )
		delete pExpr2;
	    if ( pExpr3 )
		delete pExpr3;
	    
	}	
	break;       
    }
    case CegoPredicate::ISLIKE:
    case CegoPredicate::ISNOTLIKE:
    case CegoPredicate::ISNCLIKE:
    case CegoPredicate::ISNOTNCLIKE:
    {
	CegoExpr* pExpr1=0;
	if ( _pExpr1 )
	{
	    pExpr1 = reduceExpr(aliasList, _pExpr1);
	}

	if ( pExpr1  )
	{
	    if ( _mode == CegoPredicate::ISLIKE )
		return new CegoPredicate(pExpr1, _pattern, false, true);
	    if ( _mode == CegoPredicate::ISNOTLIKE )
		return new CegoPredicate(pExpr1, _pattern, true, true);
	    if ( _mode == CegoPredicate::ISNCLIKE )
		return new CegoPredicate(pExpr1, _pattern, false, false);
	    if ( _mode == CegoPredicate::ISNOTNCLIKE )
		return new CegoPredicate(pExpr1, _pattern, true, false);	    	    
	}
	break;
    }
    case CegoPredicate::IN:
    case CegoPredicate::NOTIN:
    {
	bool isValid=true;
	
	CegoExpr* pExpr1=0;
	ListT<CegoExpr*> exprList;
	
	if ( _pExpr1 )
	{
	    pExpr1 = reduceExpr(aliasList, _pExpr1);
	}

	if ( pExpr1 )
	{	  
	    CegoExpr** pInExpr = _exprList.First();
	    while ( pInExpr && isValid )
	    {
		CegoExpr* pExpr = reduceExpr(aliasList, *pInExpr);
		if ( pExpr )
		    exprList.Insert(pExpr);
		else
		    isValid = false;
		pInExpr = _exprList.Next();
	    }
	}
	if ( pExpr1 && isValid )
	{
	    if ( _mode == CegoPredicate::IN )
		return new CegoPredicate(pExpr1, exprList, false);
	    if ( _mode == CegoPredicate::NOTIN )
		return new CegoPredicate(pExpr1, exprList, true);
	}
	else
	{
	    if ( pExpr1 )
		delete pExpr1;
	    CegoExpr** pInExpr = exprList.First();
	    while ( pInExpr  )
	    {
		delete *pInExpr;
		pInExpr = exprList.Next();
	    }	    
	}
	break;
    }
    case CegoPredicate::NULLCOMP:
    case CegoPredicate::NOTNULLCOMP:
    {

	CegoExpr* pExpr1=0;
	if ( _pExpr1 )
	{
	    pExpr1 = reduceExpr(aliasList, _pExpr1);
	}
	
	if ( pExpr1  )
	{	    
	    if ( _mode == CegoPredicate::NULLCOMP )
		return new CegoPredicate(pExpr1, true);
	    if ( _mode == CegoPredicate::NOTNULLCOMP )
		return new CegoPredicate(pExpr1, false);
	}
	break;
    }
    case CegoPredicate::INSUB:
    case CegoPredicate::NOTINSUB:
    case CegoPredicate::EXISTSCOMP:
    {
	// not handled
	break;
    }
    case CegoPredicate::EXPRONLY:
    {
	CegoExpr* pExpr1=0;
	if ( _pExpr1 )
	{
	    pExpr1 = reduceExpr(aliasList, _pExpr1);
	}
		
	if ( pExpr1 )
	{
	    return new CegoPredicate(pExpr1);
	}
	break;
    }
    }
    return 0;
}

CegoExpr* CegoPredicate::mapExpr(const Chain& viewAlias, const ListT<CegoExpr*>& exprList, CegoExpr* pExpr) const
{
    if ( pExpr->checkConst() )
	return pExpr->clone();

    CegoCondition* pC = pExpr->checkCondition();
    if ( pC )
    {
	bool mapOk=true;
	
	CegoPredicate *pLeft=0;
	if ( pC->Left() )
	{
	    pLeft = pC->Left()->map(viewAlias, exprList);
	    if ( pLeft == 0 )
	    {
		mapOk=false;
	    }
	}
	CegoPredicate *pRight=0;
	if ( pC->Right() )
	{
	    pRight = pC->Right()->map(viewAlias, exprList);
	    if ( pRight == 0 )
	    {
		mapOk=false;
	    }
	}

	if ( mapOk )
	{
	    CegoCondition* pMapCond = new CegoCondition(pC->getCondType(), pLeft, pRight);
	    return new CegoExpr( new CegoTerm(  new CegoFactor(pMapCond)));	    
	}
	else
	{
	    if ( pLeft )
		delete pLeft;
	    if ( pRight )
		delete pRight;
	    return 0;
	}
    }

    return pExpr->map(viewAlias, exprList);
    
}

CegoExpr* CegoPredicate::reduceExpr(const ListT<Chain>& aliasList, CegoExpr* pExpr) const
{
    if ( pExpr->checkConst() )
	return pExpr->clone();

    CegoCondition* pC = pExpr->checkCondition();
    if ( pC )
    {	
	CegoPredicate *pLeft=0;
	CegoPredicate *pRight=0;
	if ( pC->Left() )
	{
	    pLeft = pC->Left()->getReduced(aliasList);
	}

	if ( pC->Right() )
	{
	    pRight = pC->Right()->getReduced(aliasList);	    
	}

	if ( pLeft && pRight )
	{
	    CegoCondition* pReducedCond = new CegoCondition(pC->getCondType(), pLeft, pRight);
	    return new CegoExpr( new CegoTerm(  new CegoFactor(pReducedCond)));	    
	}

	if ( pLeft && pC->getCondType() == CegoCondition::AND )
	{
	    CegoCondition* pReducedCond = new CegoCondition(CegoCondition::PRED, pLeft, 0);	    
	    return new CegoExpr( new CegoTerm(  new CegoFactor(pReducedCond)));	    
	}
	if ( pRight && pC->getCondType() == CegoCondition::AND )
	{
	    CegoCondition* pReducedCond = new CegoCondition(CegoCondition::PRED, pRight, 0);	    
	    return new CegoExpr( new CegoTerm(  new CegoFactor(pReducedCond)));	    
	}

	if ( pLeft )
	    delete pLeft;
	if ( pRight )
	    delete pRight;	
    }

    ListT<CegoAttrDesc*> refList = pExpr->getAttrRefList();
    
    bool hasForeign = false;
    CegoAttrDesc** pAD = refList.First();
    while ( pAD && hasForeign == false )
    {
	Chain *pAlias = aliasList.First();
	bool aliasFound=false;
	while ( pAlias )
	{
	    if ( (*pAD)->getTableName() == *pAlias )
	    {
		aliasFound=true;
	    }
	    pAlias = aliasList.Next();
	}
	if ( aliasFound == false )
	    hasForeign=true;
	
	pAD = refList.Next();	
    }
    
    if ( hasForeign == false )
    {
	return pExpr->clone();
    }
    return 0;
}

bool CegoPredicate::evalFields(CegoComparison comp, const CegoFieldValue& f1, const CegoFieldValue& f2)
{
    switch (comp)
    {
    case EQUAL:
	return ( f1 == f2 );
    case NOT_EQUAL:
	return ( f1 != f2 );
    case LESS_THAN:
	return ( f1 < f2 );
    case MORE_THAN:
	return ( f1 > f2 );
    case LESS_EQUAL_THAN:
	return ( f1 <= f2 );
    case MORE_EQUAL_THAN:
	return ( f1 >= f2 );
    default:
        throw Exception(EXLOC, Chain("Unknown comparison"));
    }
}

bool CegoPredicate::evalBetween(const CegoFieldValue& f1, const CegoFieldValue& f2, const CegoFieldValue& f3)
{
    if ( f1 >= f2 && f1 <= f3 )
	return true;
    return false;
}

void CegoPredicate::setAggregationValue(ListT<CegoField>& jfl)
{
    switch (_mode )
    {
    case CegoPredicate::CONDITION:
    {
	_pC->setAggregationValue(jfl);
	break;
    }
    case CegoPredicate::NOTPRED:
    {
	_pNotPred->setAggregationValue(jfl);
	break;
    }
    case CegoPredicate::EXPRCOMP:
    {
	setAggregationValueForExpr(_pExpr1, jfl);
	setAggregationValueForExpr(_pExpr2, jfl);
	break;
    }
    case CegoPredicate::BETWEEN:
    {
	setAggregationValueForExpr(_pExpr1, jfl);
	setAggregationValueForExpr(_pExpr2, jfl);
	setAggregationValueForExpr(_pExpr3, jfl);
	break;
    }
    case CegoPredicate::ISLIKE:
    case CegoPredicate::ISNOTLIKE:
    case CegoPredicate::ISNCLIKE:
    case CegoPredicate::ISNOTNCLIKE:
    {
	setAggregationValueForExpr(_pExpr1, jfl);
	break;
    }
    case CegoPredicate::INSUB:
    case CegoPredicate::NOTINSUB:
    {
	// still not clear, if this case is useful 
	setAggregationValueForExpr(_pExpr1, jfl);
	// _pSelect->getFieldList(fl);
	break;
    }
    case CegoPredicate::IN:
    case CegoPredicate::NOTIN:
    {
	setAggregationValueForExpr(_pExpr1, jfl);
	break;
    }
    case CegoPredicate::EXISTSCOMP:
    {
	// still not clear, if this case is useful 
	// _pSelect->getFieldList(fl);
	break;
    }
    case CegoPredicate::EXPRONLY:
    case CegoPredicate::NULLCOMP:
    case CegoPredicate::NOTNULLCOMP:
    {
	setAggregationValueForExpr(_pExpr1, jfl);
	break;
    }
    }
}

void CegoPredicate::setAggregationValueForExpr(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();
    }
}

CegoPredicate* CegoPredicate::clone(bool isAttrRef)
{    
    if ( _mode == CegoPredicate::EXPRCOMP )
    {
	return new CegoPredicate(_pExpr1->clone(isAttrRef), _pExpr2->clone(isAttrRef), _comp);
    }
    else if ( _mode == CegoPredicate::EXPRONLY )
    {
	return new CegoPredicate(_pExpr1->clone(isAttrRef));
    }
    else if ( _mode == CegoPredicate::BETWEEN )
    {
	return new CegoPredicate(_pExpr1->clone(isAttrRef), _pExpr2->clone(isAttrRef), _pExpr3->clone(isAttrRef));
    }
    else if ( _mode == CegoPredicate::ISLIKE )
    {
	return new CegoPredicate(_pExpr1->clone(isAttrRef), _pattern, false, true);
    }
    else if ( _mode == CegoPredicate::ISNOTLIKE )
    {
	return new CegoPredicate(_pExpr1->clone(isAttrRef), _pattern, true, true);
    }
    else if ( _mode == CegoPredicate::ISNCLIKE )
    {
	return new CegoPredicate(_pExpr1->clone(isAttrRef), _pattern, false, false);
    }
    else if ( _mode == CegoPredicate::ISNOTNCLIKE )
    {
	return new CegoPredicate(_pExpr1->clone(isAttrRef), _pattern, true, false);
    }
    else if ( _mode == CegoPredicate::CONDITION )
    {
	return new CegoPredicate(_pC->clone(isAttrRef));
    }
    else if ( _mode == CegoPredicate::NOTPRED )
    {
	return new CegoPredicate(_pNotPred->clone(isAttrRef));
    }
    else if ( _mode == CegoPredicate::EXISTSCOMP )
    {
	return new CegoPredicate(_pSelect->clone(isAttrRef));
    }
    else if ( _mode == CegoPredicate::INSUB )
    {
	return new CegoPredicate(_pExpr1->clone(isAttrRef), _pSelect->clone(isAttrRef), false);
    }
    else if ( _mode == CegoPredicate::NOTINSUB )
    {
	return new CegoPredicate(_pExpr1->clone(isAttrRef), _pSelect->clone(isAttrRef), true);
    }
    else if ( _mode == CegoPredicate::IN )
    {
	ListT<CegoExpr*> exprList;

	CegoExpr** pExpr = _exprList.First();
	while ( pExpr )
	{
	    exprList.Insert((*pExpr)->clone());
	    pExpr = _exprList.Next();
	}
	return new CegoPredicate(_pExpr1->clone(isAttrRef), exprList, false);
    }
    else if ( _mode == CegoPredicate::NOTIN )
    {
	ListT<CegoExpr*> exprList;

	CegoExpr** pExpr = _exprList.First();
	while ( pExpr )
	{
	    exprList.Insert((*pExpr)->clone());
	    pExpr = _exprList.Next();
	}
	return new CegoPredicate(_pExpr1->clone(isAttrRef), exprList, true);
    }
    else if ( _mode == CegoPredicate::NULLCOMP )
    {
	return new CegoPredicate(_pExpr1->clone(isAttrRef), true);
    }
    else if ( _mode == CegoPredicate::NOTNULLCOMP )
    {
	return new CegoPredicate(_pExpr1->clone(isAttrRef), false);
    }
    
    throw Exception(EXLOC, "Clone not implemented");
}

Chain CegoPredicate::getId(CegoProcBlock *pBlock) const
{
    Chain s;

    switch (_mode )
    {
    case CegoPredicate::CONDITION:
    {
	if (_pC->Left())
	{
	    s = Chain("(");
	    s += _pC->Left()->getId(pBlock);

	    switch(_pC->getCondType())
	    {
	    case CegoCondition::AND:
		s += Chain("a");
		s += _pC->Right()->getId(pBlock);
		break;
	    case CegoCondition::OR:
		s += Chain("o");
		s += _pC->Right()->getId(pBlock);
		break;
	    case CegoCondition::PRED:
		break;
	    }

	    s += Chain(")");
	}
	break;
    }
    case CegoPredicate::NOTPRED:
    {
	s = Chain("n") + _pNotPred->getId(pBlock);
	break;
    }
    case CegoPredicate::EXPRCOMP:
    {	
	s = _pExpr1->getId(pBlock);
	
	switch (_comp)
	{
	case EQUAL:
	    s += "=";
	    break;
	case NOT_EQUAL:
	    s += "!=";
	    break;
	case LESS_THAN:
	    s += "<";
	    break;
	case MORE_THAN:
	    s += ">";
	    break;
	case LESS_EQUAL_THAN:
	    s += "<=";
	    break;
	case MORE_EQUAL_THAN:
	    s += ">=";
	    break;
	}
	s +=  _pExpr2->getId(pBlock);
	break;
    }
    case CegoPredicate::BETWEEN:
    {	
	s = _pExpr2->getId(pBlock);
	s += Chain("bw");
	s +=  _pExpr1->getId(pBlock);
	s += Chain("a");
	s +=  _pExpr3->getId(pBlock);
	break;
    }
    case CegoPredicate::ISLIKE:
    {
	s = _pExpr1->getId(pBlock);
	s += Chain("l");
	s += Chain("'") + _pattern + Chain("'");
	break;
    }
    case CegoPredicate::ISNOTLIKE:
    {
	s = _pExpr1->getId(pBlock);
	s += Chain("nl");
	s += Chain("'") + _pattern + Chain("'");
	break;
    }
    case CegoPredicate::ISNCLIKE:
    {
	s = _pExpr1->getId(pBlock);
	s += Chain("ncl");
	s += Chain("'") + _pattern + Chain("'");
	break;
    }
    case CegoPredicate::ISNOTNCLIKE:
    {
	s = _pExpr1->getId(pBlock);
	s += Chain("nncl");
	s += Chain("'") + _pattern + Chain("'");
	break;
    }
    case CegoPredicate::EXPRONLY:
    {
	s =  _pExpr1->getId(pBlock);
	s += Chain("oly");
	break;
    }
    case CegoPredicate::NULLCOMP:
    {
	s =  _pExpr1->getId(pBlock);
	s += Chain("n");
	break;
    }
    case CegoPredicate::NOTNULLCOMP:
    {
	s = _pExpr1->getId(pBlock);
	s += Chain("nn");
	break;
    }
    case CegoPredicate::EXISTSCOMP:
    {
	s = Chain("e");
	s += _pSelect->getQueryId();
	break;
    }
    case CegoPredicate::INSUB:
    {
	s = _pExpr1->getId(pBlock);
	s += Chain("i");
	s += Chain("(") + _pSelect->getQueryId() + Chain(")");
	break;
    }
    case CegoPredicate::NOTINSUB:
    {
	s = _pExpr1->getId(pBlock);
	s += Chain("ni");
	s += Chain("(") + _pSelect->getQueryId() + Chain(")");   
	break;
    }
    case CegoPredicate::IN:
    {
	s = _pExpr1->getId(pBlock);
	s += Chain("i");
	s += Chain("(");	
	CegoExpr **pExpr = _exprList.First();
	while ( pExpr )
	{
	    s += (*pExpr)->getId(pBlock);
	    pExpr = _exprList.Next();
	    if ( pExpr )
		s += Chain(",");
	}
	s += Chain(")");
	break;
    }
    case CegoPredicate::NOTIN:
    {
	s = _pExpr1->getId(pBlock);
	s += Chain("ni");
	s += Chain("(");	
	CegoExpr **pExpr = _exprList.First();
	while ( pExpr )
	{
	    s += (*pExpr)->getId(pBlock);
	    pExpr = _exprList.Next();
	    if ( pExpr )
		s += Chain(",");
	}
	s += Chain(")");
	break;
    }
    }
    return s;
}

Chain CegoPredicate::toChain(unsigned defTabSetId, const Chain& indent) const
{
    Chain s;

    switch (_mode )
    {
    case CegoPredicate::CONDITION:
    {
	s =  _pC->toChain(defTabSetId, indent);	
	break;
    }
    case CegoPredicate::NOTPRED:
    {
	s = Chain("not ") + _pNotPred->toChain(defTabSetId, indent + Chain(DEFAULTINDENT));
	break;
    }
    case CegoPredicate::EXPRCOMP:
    {	
	s = _pExpr1->toChain(defTabSetId, indent);
	
	switch (_comp)
	{
	case EQUAL:
	    s += " = ";
	    break;
	case NOT_EQUAL:
	    s += " != ";
	    break;
	case LESS_THAN:
	    s += " < ";
	    break;
	case MORE_THAN:
	    s += " > ";
	    break;
	case LESS_EQUAL_THAN:
	    s += " <= ";
	    break;
	case MORE_EQUAL_THAN:
	    s += " >= ";
	    break;
	}
	
	Chain addIndent;
	for ( unsigned i=1; i < (unsigned)s.length(); i++ )
	    addIndent += Chain(" ");
	
	s +=  _pExpr2->toChain(defTabSetId, indent + addIndent);
	break;
    }
    case CegoPredicate::BETWEEN:
    {	
	s = _pExpr1->toChain(defTabSetId, indent);
	s += Chain("\n") + indent;
	s += Chain("between ");

	Chain addIndent;

	addIndent = Chain(DEFAULTINDENT);
	s += _pExpr2->toChain(defTabSetId, indent + addIndent);
	s += Chain("\n") + indent;
	s += Chain("and ");	

	addIndent=Chain(DEFAULTINDENT);
	s += _pExpr3->toChain(defTabSetId, indent + addIndent);

	break;
    }
    case CegoPredicate::ISLIKE:
    {
	s = _pExpr1->toChain(defTabSetId, indent);
	s += Chain(" like ");
	s += Chain("'") + _pattern + Chain("'");
	break;
    }
    case CegoPredicate::ISNOTLIKE:
    {
	s = _pExpr1->toChain(defTabSetId, indent);
	s += Chain(" not like ");
	s += Chain("'") + _pattern + Chain("'");
	break;
    }
    case CegoPredicate::ISNCLIKE:
    {
	s = _pExpr1->toChain(defTabSetId, indent);
	s += Chain(" nclike ");
	s += Chain("'") + _pattern + Chain("'");
	break;
    }
    case CegoPredicate::ISNOTNCLIKE:
    {
	s = _pExpr1->toChain(defTabSetId, indent);
	s += Chain(" not nclike ");
	s += Chain("'") + _pattern + Chain("'");
	break;
    }
    case CegoPredicate::EXPRONLY:
    {
	s = _pExpr1->toChain(defTabSetId, indent);
	break;
    }
    case CegoPredicate::NULLCOMP:
    {
	s = _pExpr1->toChain(defTabSetId, indent);
	s += Chain(" is null ");
	break;
    }
    case CegoPredicate::NOTNULLCOMP:
    {
	s = _pExpr1->toChain(defTabSetId, indent);
	s += Chain(" is not null ");
	break;
    }
    case CegoPredicate::EXISTSCOMP:
    {
	s = Chain("exists ( ");
	s += _pSelect->toChain(defTabSetId, indent + Chain(DEFAULTINDENT)) + Chain(" )");
	break;
    }
    case CegoPredicate::INSUB:
    {
	s = _pExpr1->toChain(defTabSetId, indent);
	s += Chain(" in ( ");

	Chain addIndent;
	for ( unsigned i=1; i < (unsigned)s.length(); i++ )
	    addIndent += Chain(" ");

	s += _pSelect->toChain(defTabSetId, indent + addIndent) + Chain(" )");   
	break;
    }
    case CegoPredicate::NOTINSUB:
    {
	s = _pExpr1->toChain(defTabSetId, indent);
	s += Chain(" not in ( ");

	Chain addIndent;
	for ( unsigned i=1; i < (unsigned)s.length(); i++ )
	    addIndent += Chain(" ");

	s += _pSelect->toChain(defTabSetId, indent + addIndent) + Chain(" )");   
	break;
    }
    case CegoPredicate::IN:
    {
	s = _pExpr1->toChain(defTabSetId, indent);
	s += Chain(" in ( ");

	CegoExpr **pExpr = _exprList.First();
	while ( pExpr )
	{
	    s += (*pExpr)->toChain(defTabSetId);
	    pExpr = _exprList.Next();
	    if ( pExpr )
		s += Chain(",");
	}
	s += Chain(")");

	break;
    }
    case CegoPredicate::NOTIN:
    {
	s = _pExpr1->toChain(defTabSetId, indent);
	s += Chain(" not in ( ");

	CegoExpr **pExpr = _exprList.First();
	while ( pExpr )
	{
	    s += (*pExpr)->toChain(defTabSetId);
	    pExpr = _exprList.Next();
	    if ( pExpr )
		s += Chain(",");
	}
	s += Chain(")");

	break;
    }
    }
    return s;
}

Chain CegoPredicate::dbFormat(CegoDatabaseFormater *pForm)
{
    return pForm->formatPred(_mode, _pExpr1, _pExpr2, _pExpr3, _exprList, _comp, _pattern, _pC, _pNotPred, _pSelect);
}

ostream& operator << (ostream& s, const CegoPredicate& p)
{
    s << p.toChain(0);
    return s;
}
