///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoQueryHelper.cc
// ------------------
// Cego query helper implementation
//     
// Design and Implementation by Bjoern Lemke
//     
// (C)opyright 2000-2025 Bjoern Lemke
//
// IMPLEMENTATION MODULE
//
// Class: CegoQueryHelper
//
// Description: The CegoQueryHelper class provides several utility methods
//              which are used for tuple retrieval and evalution
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

// base includes
#include <lfcbase/BigDecimal.h>
#include <lfcbase/Datetime.h>

// cego includes
#include "CegoQueryHelper.h"
#include "CegoXMLdef.h"
#include "CegoSelect.h"
#include "CegoTypeConverter.h"

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

unsigned __dateLength;

CegoQueryHelper::CegoQueryHelper()
{
}

CegoQueryHelper::~CegoQueryHelper()
{
}

CegoQueryHelper::AttrCondMatch CegoQueryHelper::checkAttrCond(CegoAttrCond& ac, 
							    CegoPredicate* pP, 
							    const ListT<CegoField>& schema,
							    ListT<CegoField>* flArray, 
							    unsigned flSize, 
							    CegoProcBlock *pBlock)
{
    AttrCondMatch m = evalAttrCond(ac, pP, schema, flArray, flSize, pBlock);
    
    if ( ac.numComp() == 0 )
	m = INAPP;
    return m;
}

CegoQueryHelper::AttrCondMatch CegoQueryHelper::evalAttrCond(CegoAttrCond& ac, 
							     CegoPredicate* pP, 
							     const ListT<CegoField>& schema,
							     ListT<CegoField>* flArray, 
							     unsigned flSize, 
							     CegoProcBlock *pBlock)
{    
    if (pP->getCondition())
    {
	return evalAttrCondbyCondition(ac, pP->getCondition(), schema, flArray, flSize, pBlock);
    }
    else if (pP->getMode() == CegoPredicate::EXPRCOMP)
    {	
	CegoAttrDesc* pAttrDesc1;
	CegoAttrDesc* pAttrDesc2;
	
	pAttrDesc1 = pP->getExpr1()->checkAttr();
	pAttrDesc2 = pP->getExpr2()->checkAttr();
	ListT<CegoAttrDesc*> attrRefList1 = pP->getExpr1()->getAttrRefList();
	ListT<CegoAttrDesc*> attrRefList2 = pP->getExpr2()->getAttrRefList();

	if ( pAttrDesc1 && pAttrDesc2 )
	{	    
	    if ( ac.isAnd() == false )
	    {
		ac.clean();
		ac.setAnd(true);
	    }
	    
	    CegoField* pF = schema.First();
	    
	    while (pF)
	    {		
		if ( ((Chain)pAttrDesc1->getTableName() == (Chain)pF->getTableName() ||
		      (Chain)pAttrDesc1->getTableName() == (Chain)pF->getTableAlias() ||
		      pAttrDesc1->getTableName() == Chain())
		     && (Chain)pAttrDesc1->getAttrName() == (Chain)pF->getAttrName() )
		{
		    for ( unsigned i=0; i<flSize; i++)
		    {
			CegoField* pFB = flArray[i].First();
			while (pFB)
			{			    
			    if (((Chain)pAttrDesc2->getTableName() == (Chain)pFB->getTableName() ||
				 (Chain)pAttrDesc2->getTableName() == (Chain)pFB->getTableAlias() ||
				 pAttrDesc2->getTableName() == Chain())
				&& (Chain)pAttrDesc2->getAttrName() == (Chain)pFB->getAttrName())
			    {
				ac.add(CegoAttrComp(pF->getTableAlias(), 
						    pF->getAttrName(), 
						    pP->getComparison(),
						    *pAttrDesc2));
				return COMPLETE;
			    }
			    pFB = flArray[i].Next();
			}
		    }
		}

		if ( ((Chain)pAttrDesc2->getTableName() == (Chain)pF->getTableName() ||
		      (Chain)pAttrDesc2->getTableName() == (Chain)pF->getTableAlias() ||
		      pAttrDesc2->getTableName() == Chain())
		     && (Chain)pAttrDesc2->getAttrName() == (Chain)pF->getAttrName() )
		{			
		    for ( unsigned i=0; i<flSize; i++)
		    {
			CegoField* pFB = flArray[i].First();
			while (pFB)			   			    
			{			   
			    if (((Chain)pAttrDesc1->getTableName() == (Chain)pFB->getTableName() ||
				 (Chain)pAttrDesc1->getTableName() == (Chain)pFB->getTableAlias() ||
				 pAttrDesc1->getTableName() == Chain())
				&& (Chain)pAttrDesc1->getAttrName() == (Chain)pFB->getAttrName())
			    {
				// we have to map comparison 
				CegoComparison comp = pP->getComparison();
				if ( comp == LESS_THAN )
				    comp = MORE_THAN;
				else if ( comp == MORE_THAN )
				    comp = LESS_THAN;
				else if ( comp == LESS_EQUAL_THAN )
				    comp = MORE_EQUAL_THAN;
				else if ( comp == MORE_EQUAL_THAN )
				    comp = LESS_EQUAL_THAN;

				ac.add(CegoAttrComp(pF->getTableAlias(), 
						    pF->getAttrName(), 
						    comp,
						    *pAttrDesc1));
				return COMPLETE;
			    }
			    pFB = flArray[i].Next();
			}
		    }
		}
		pF = schema.Next();
	    }
	    return PARTIAL;
	}
	else if ( pAttrDesc1 && attrRefList2.Size() == 0  )
	{
	    if ( ac.isAnd() == false )
	    {
		ac.clean();
		ac.setAnd(true);
	    }

	    CegoField* pF = schema.First();   
	    while (pF)
	    { 
		if ((pAttrDesc1->getTableName() == (Chain)pF->getTableName() ||
		     pAttrDesc1->getTableName() == (Chain)pF->getTableAlias() ||
		     pAttrDesc1->getTableName() == Chain())
		    && pAttrDesc1->getAttrName() == (Chain)pF->getAttrName())
		{
		    ac.add(CegoAttrComp(pF->getTableAlias(), 
					pF->getAttrName(),
					pP->getComparison(),
					pP->getExpr2()->evalFieldValue(0, pBlock)));
		    return COMPLETE;
		}
		pF = schema.Next();
	    }
	    return PARTIAL;
	}
	else if ( pAttrDesc2 && attrRefList1.Size() == 0 && ac.isAnd() )
	{
	    CegoField* pF = schema.First();	    
	    while (pF)
	    {
		if ((pAttrDesc2->getTableName() == (Chain)pF->getTableName() ||
		     pAttrDesc2->getTableName() == (Chain)pF->getTableAlias() ||
		     pAttrDesc2->getTableName() == Chain())
		    && pAttrDesc2->getAttrName() == (Chain)pF->getAttrName())
		{
		    // we have to map comparison 
		    CegoComparison comp = pP->getComparison();
		    if ( comp == LESS_THAN )
			comp = MORE_THAN;
		    else if ( comp == MORE_THAN )
			comp = LESS_THAN;
		    else if ( comp == LESS_EQUAL_THAN )
			comp = MORE_EQUAL_THAN;
		    else if ( comp == MORE_EQUAL_THAN )
			comp = LESS_EQUAL_THAN;

		    ac.add(CegoAttrComp(pF->getTableAlias(), 
					pF->getAttrName(),
					comp,
					pP->getExpr1()->evalFieldValue(0, pBlock)));
		    return COMPLETE;
		}
		pF = schema.Next();
	    }
	    return PARTIAL;
	}
	else
	{
	    return PARTIAL;
	}
    }
    else if (pP->getMode() == CegoPredicate::BETWEEN)
    {	
	CegoAttrDesc* pAttrDesc1 = pP->getExpr1()->checkAttr();
	CegoAttrDesc* pAttrDesc2 = pP->getExpr2()->checkAttr();
	CegoAttrDesc* pAttrDesc3 = pP->getExpr3()->checkAttr();

	ListT<CegoAttrDesc*> attrRefList1 = pP->getExpr1()->getAttrRefList();
	ListT<CegoAttrDesc*> attrRefList2 = pP->getExpr2()->getAttrRefList();
	ListT<CegoAttrDesc*> attrRefList3 = pP->getExpr3()->getAttrRefList();

	if ( pAttrDesc1  )
	{

	    if ( ac.isAnd() == false )
	    {
		ac.clean();
		ac.setAnd(true);
	    }

	    
	    CegoField* pF = schema.First(); 
	    while (pF)
	    {		
		if ((pAttrDesc1->getTableName() == (Chain)pF->getTableName() ||
		     pAttrDesc1->getTableName() == (Chain)pF->getTableAlias() ||
		     pAttrDesc1->getTableName() == Chain())
		    && pAttrDesc1->getAttrName() == (Chain)pF->getAttrName())
		{
		    if (  attrRefList2.Size() == 0 && attrRefList3.Size() == 0 ) 
                    { 
                        ac.add(CegoAttrComp(pF->getTableAlias(), 
                                            pF->getAttrName(), 
                                            pP->getExpr2()->evalFieldValue(0, pBlock), 
                                            pP->getExpr3()->evalFieldValue(0, pBlock))); 
                    } 
                    else if ( pAttrDesc2 && attrRefList3.Size() == 0 ) 
                    { 			
                        ac.add(CegoAttrComp(pF->getTableAlias(), 
                                            pF->getAttrName(), 
                                            *pAttrDesc2, 
                                            pP->getExpr3()->evalFieldValue(0, pBlock)));
                    } 
                    else if (  attrRefList2.Size() == 0 &&  pAttrDesc3  ) 
                    { 
                        ac.add(CegoAttrComp(pF->getTableAlias(), 
                                            pF->getAttrName(), 
                                            pP->getExpr2()->evalFieldValue(0, pBlock), 
                                            *pAttrDesc3));			
                    } 
                    else if ( pAttrDesc2 && pAttrDesc3 ) 
                    { 
                        ac.add(CegoAttrComp(pF->getTableAlias(), 
                                            pF->getAttrName(), 
                                            *pAttrDesc2, 
                                            *pAttrDesc3));
                    } 
                    else 
                    { 
                        return PARTIAL; 
                    } 

		    return COMPLETE;
		}
		pF = schema.Next();
	    }
	    return PARTIAL;
	}
	else
	{
	    return PARTIAL;
	}
    }
    else if (pP->getMode() == CegoPredicate::ISLIKE)
    {
	CegoAttrDesc* pAttrDesc;	
	pAttrDesc = pP->getExpr1()->checkAttr();
	if ( pAttrDesc && ac.isAnd() )
	{
	    CegoField* pF = schema.First(); 
	    while (pF)
	    {		
		if ((pAttrDesc->getTableName() == (Chain)pF->getTableName() ||
		     pAttrDesc->getTableName() == (Chain)pF->getTableAlias() ||
		     pAttrDesc->getTableName() == Chain())
		    && pAttrDesc->getAttrName() == (Chain)pF->getAttrName())
		{
		    ac.add(CegoAttrComp(pAttrDesc->getTableName(), pAttrDesc->getAttrName(), pP->getPattern(), false, true));
		    return COMPLETE;
		}
		pF = schema.Next();
	    }
	    return PARTIAL;
	}
	else
	{
	    return PARTIAL;
	}
    }
    else if (pP->getMode() == CegoPredicate::ISNOTLIKE)
    {
	CegoAttrDesc* pAttrDesc;	
	pAttrDesc = pP->getExpr1()->checkAttr();
	if ( pAttrDesc && ac.isAnd() )
	{
	    CegoField* pF = schema.First(); 
	    while (pF)
	    {		
		if ((pAttrDesc->getTableName() == (Chain)pF->getTableName() ||
		     pAttrDesc->getTableName() == (Chain)pF->getTableAlias() ||
		     pAttrDesc->getTableName() == Chain())
		    && pAttrDesc->getAttrName() == (Chain)pF->getAttrName())
		{
		    ac.add(CegoAttrComp(pAttrDesc->getTableName(), pAttrDesc->getAttrName(), pP->getPattern(), true, true));
		    return COMPLETE;
		}
		pF = schema.Next();
	    }
	    return PARTIAL;
	}
	else
	{
	    return PARTIAL;
	}
    }
    else if (pP->getMode() == CegoPredicate::ISNCLIKE)
    {
	CegoAttrDesc* pAttrDesc;	
	pAttrDesc = pP->getExpr1()->checkAttr();
	if ( pAttrDesc && ac.isAnd() )
	{
	    CegoField* pF = schema.First(); 
	    while (pF)
	    {		
		if ((pAttrDesc->getTableName() == (Chain)pF->getTableName() ||
		     pAttrDesc->getTableName() == (Chain)pF->getTableAlias() ||
		     pAttrDesc->getTableName() == Chain())
		    && pAttrDesc->getAttrName() == (Chain)pF->getAttrName())
		{
		    ac.add(CegoAttrComp(pAttrDesc->getTableName(), pAttrDesc->getAttrName(), pP->getPattern(), false, false));
		    return COMPLETE;
		}
		pF = schema.Next();
	    }
	    return PARTIAL;
	}
	else
	{
	    return PARTIAL;
	}
    }
    else if (pP->getMode() == CegoPredicate::ISNOTNCLIKE)
    {
	CegoAttrDesc* pAttrDesc;	
	pAttrDesc = pP->getExpr1()->checkAttr();
	if ( pAttrDesc && ac.isAnd() )
	{
	    CegoField* pF = schema.First(); 
	    while (pF)
	    {		
		if ((pAttrDesc->getTableName() == (Chain)pF->getTableName() ||
		     pAttrDesc->getTableName() == (Chain)pF->getTableAlias() ||
		     pAttrDesc->getTableName() == Chain())
		    && pAttrDesc->getAttrName() == (Chain)pF->getAttrName())
		{
		    ac.add(CegoAttrComp(pAttrDesc->getTableName(), pAttrDesc->getAttrName(), pP->getPattern(), true, false));
		    return COMPLETE;
		}
		pF = schema.Next();
	    }
	    return PARTIAL;
	}
	else
	{
	    return PARTIAL;
	}
    }
    else if (pP->getMode() == CegoPredicate::NULLCOMP)
    {
	CegoAttrDesc* pAttrDesc;	
	pAttrDesc = pP->getExpr1()->checkAttr();
	if ( pAttrDesc && ac.isAnd() )
	{
	    CegoField* pF = schema.First(); 
	    while (pF)
	    {		
		if ((pAttrDesc->getTableName() == (Chain)pF->getTableName() ||
		     pAttrDesc->getTableName() == (Chain)pF->getTableAlias() ||
		     pAttrDesc->getTableName() == Chain())
		    && pAttrDesc->getAttrName() == (Chain)pF->getAttrName())
		{		    
		    CegoFieldValue nullValue;
		    ac.add(CegoAttrComp(pAttrDesc->getTableName(), pAttrDesc->getAttrName(), EQUAL, nullValue));
		    return COMPLETE;
		}
		pF = schema.Next();
	    }
	    return PARTIAL;
	}
	else
	{
	    return PARTIAL;	    
	}
    }
    else if (pP->getMode() == CegoPredicate::NOTNULLCOMP)
    {
	CegoAttrDesc* pAttrDesc;	
	pAttrDesc = pP->getExpr1()->checkAttr();
	if ( pAttrDesc && ac.isAnd() )
	{
	    CegoField* pF = schema.First(); 
	    while (pF)
	    {		
		if ((pAttrDesc->getTableName() == (Chain)pF->getTableName() ||
		     pAttrDesc->getTableName() == (Chain)pF->getTableAlias() ||
		     pAttrDesc->getTableName() == Chain())
		    && pAttrDesc->getAttrName() == (Chain)pF->getAttrName())
		{		    
		    CegoFieldValue nullValue;
		    ac.add(CegoAttrComp(pAttrDesc->getTableName(), pAttrDesc->getAttrName(), NOT_EQUAL, nullValue));
		    return COMPLETE;
		}
		pF = schema.Next();
	    }
	    return PARTIAL;
	}
	else
	{
	    return PARTIAL;	    
	}
    }
    else if (pP->getMode() == CegoPredicate::EXISTSCOMP)
    {
	return PARTIAL;	    
    }
    else if (pP->getMode() == CegoPredicate::IN)
    {

	CegoAttrDesc* pAttrDesc1 = pP->getExpr1()->checkAttr();
	ListT<CegoAttrDesc*> attrRefList1 = pP->getExpr1()->getAttrRefList();
	
	if ( pAttrDesc1 && ( ac.numComp() == 0 || ac.hasIndexCandidate() == false ) )
	{
	    ac.clean();
	    ac.setAnd(false);
	    	     
	    Chain tabAlias;
	    Chain attrName;
	    
	    CegoField* pF = schema.First(); 
	    while (pF)
	    {		
		if ((pAttrDesc1->getTableName() == (Chain)pF->getTableName() ||
		     pAttrDesc1->getTableName() == (Chain)pF->getTableAlias() ||
		     pAttrDesc1->getTableName() == Chain())
		    && pAttrDesc1->getAttrName() == (Chain)pF->getAttrName())
		{		    
		    tabAlias = pF->getTableAlias();
		    attrName = pF->getAttrName();
		}
		
		pF = schema.Next(); 
		
	    }
	    
	    if ( tabAlias == Chain() )
		return PARTIAL;
	    
	    
	    CegoExpr** pExpr = pP->getExprList().First();
	    while ( pExpr )
	    {
		
		CegoAttrDesc* pInAttrDesc = (*pExpr)->checkAttr();
		ListT<CegoAttrDesc*> inAttrRefList = (*pExpr)->getAttrRefList();

		if ( pInAttrDesc )
		{
		    bool attrFound=false;
		    
		    CegoField* pF = schema.First(); 
		    while (pF)
		    {
			
			if ((pInAttrDesc->getTableName() == (Chain)pF->getTableName() ||
			     pInAttrDesc->getTableName() == (Chain)pF->getTableAlias() ||
			     pInAttrDesc->getTableName() == Chain())
			    && pInAttrDesc->getAttrName() == (Chain)pF->getAttrName())
			{		    
			    ac.add(CegoAttrComp(tabAlias,
						attrName,
						EQUAL,	
						*pInAttrDesc));
			    attrFound=true;
			    
			}
			pF = schema.Next();
		    }

		    if ( attrFound == false )
		    {
			for ( unsigned i=0; i<flSize; i++)
			{
			    CegoField* pFB = flArray[i].First();
			    while (pFB)
			    {
				
				if ( (Chain)pInAttrDesc->getTableName() == (Chain)pFB->getTableName() ||
				     (Chain)pInAttrDesc->getTableName() == (Chain)pFB->getTableAlias() ||
				     ( pInAttrDesc->getTableName() == Chain()
				       && (Chain)pInAttrDesc->getAttrName() == (Chain)pFB->getAttrName()) )
				{				
				    ac.add( CegoAttrComp(tabAlias, 
							 attrName,
							 EQUAL,
							 *pInAttrDesc));
				    attrFound=true;
				}
				pFB = flArray[i].Next();
			    }
			}
		    }

		    if ( attrFound == false )
			return INAPP;

		}
		else if ( inAttrRefList.Size() == 0 )		    
		{
		    ac.add(CegoAttrComp(tabAlias, 
					attrName, 
					EQUAL,
					(*pExpr)->evalFieldValue(0, pBlock)));
		}
		
		pExpr = pP->getExprList().Next();
	    }
	    
	    return COMPLETE;
	}
	else
	{
	    return PARTIAL;
	}
    }
    else if (pP->getMode() == CegoPredicate::NOTIN)
    {
	return PARTIAL;	    
    }
    else if (pP->getMode() == CegoPredicate::INSUB)
    {
	return PARTIAL;	    
    }
    else if (pP->getMode() == CegoPredicate::NOTINSUB)
    {
	return PARTIAL;	    
    }
    else if (pP->getMode() == CegoPredicate::NOTPRED)
    {
	return PARTIAL;
    }
    else
    {
	return PARTIAL;
    }

    return COMPLETE;
}

CegoQueryHelper::AttrCondMatch CegoQueryHelper::evalAttrCondbyCondition(CegoAttrCond& ac,
									CegoCondition* pC,
									const ListT<CegoField>& schema,
									ListT<CegoField>* flArray, 
									unsigned flSize, 
									CegoProcBlock* pBlock)
{
    
    if ( pC->getCondType() == CegoCondition::OR)
    {
	return INAPP;	
    }

    AttrCondMatch m1, m2;
    m1 = COMPLETE;
    m2 = COMPLETE;
    if ( pC->Left() )
    {
	m1 = evalAttrCond(ac, pC->Left(), schema, flArray, flSize, pBlock);
    }
    if ( pC->Right() )
    {
	m2 = evalAttrCond(ac, pC->Right(), schema, flArray, flSize, pBlock);
    }
    
    if ( m1 == INAPP || m2 == INAPP )
	return INAPP;
    if ( m1 == PARTIAL || m2 == PARTIAL )
	return PARTIAL;
    
    return COMPLETE;
}

void CegoQueryHelper::makeCNF(CegoCondition* pC)
{
    if ( pC )
    {
	if (pC->Left()->getCondition())
	{
	    makeCNF(pC->Left()->getCondition());
	}
	if ( pC->Right() )
	{
	    if (pC->Right()->getCondition())
	    {
		makeCNF(pC->Right()->getCondition());
	    }
	}
	if ( pC->getCondType() == CegoCondition::AND )
	{
	    // nothing to do
	} 
	else if ( pC->getCondType() == CegoCondition::OR )
	{
	    if ( pC->Left()->getCondition() )
	    {
		CegoCondition *pLC = pC->Left()->getCondition();
		if (pLC->getCondType() == CegoCondition::AND)
		{
		    pC->setCondType(CegoCondition::AND);
		    CegoCondition* pNC = new CegoCondition(CegoCondition::OR);
		    pNC->setLeft(pLC->Right());
		    pNC->setRight(pC->Right());
		    CegoPredicate* pNP = new CegoPredicate(pNC);
		    pC->setRight(pNP);
		    pLC->setCondType(CegoCondition::OR);
		    
		    pLC->setRight(pNC->Right()->clone());
		    
		    makeCNF(pC->Left()->getCondition());
		    makeCNF(pC->Right()->getCondition());
		}
		else
		{
		    makeCNF(pC->Left()->getCondition());
		}		
	    } 
	    else if ( pC->Right()->getCondition() )
	    {
		CegoCondition *pRC = pC->Right()->getCondition();
		if (pRC->getCondType() == CegoCondition::AND)
		{
		    pC->setCondType(CegoCondition::AND);
		    CegoCondition* pNC = new CegoCondition(CegoCondition::OR);
		    pNC->setLeft(pC->Left());
		    pNC->setRight(pRC->Left());
		    CegoPredicate* pNP = new CegoPredicate(pNC);
		    pC->setLeft(pNP);
		    pRC->setCondType(CegoCondition::OR);
		    pRC->setLeft(pNC->Left()->clone());	    
		    
		    makeCNF(pC->Left()->getCondition());
		    makeCNF(pC->Right()->getCondition());
		}
		else
		{
		    makeCNF(pC->Right()->getCondition());
		}
		
	    }
	}
    }
}

void CegoQueryHelper::createConjunctionList(CegoPredicate* pPred, ListT<CegoPredicate*>* pConjunctionList)
{
    if (pPred)
    {
	CegoCondition* pC = pPred->getCondition();	
	if (pC)
	{
	    if (pC->getCondType() == CegoCondition::AND)
	    {
		createConjunctionList(pC->Left(), pConjunctionList);
		createConjunctionList(pC->Right(), pConjunctionList);
	    }
	    else
	    {
		pConjunctionList->Insert(pPred);
	    }
	}
	else
	{
	    pConjunctionList->Insert(pPred);
	}
    }
}

Chain CegoQueryHelper::condToChain(CegoCondition* pC, unsigned depth)
{
    Chain s;
    if (pC->Left())
    {
	s = predToChain(pC->Left(), depth+1);
	for (unsigned i=0;i<depth;i++)
	    s += Chain(" ");
	switch(pC->getCondType())
	{
	case CegoCondition::AND:
	    s += Chain(" AND ");
	    break;
	case CegoCondition::OR:
	    s += Chain(" OR ");
	    break;
	case CegoCondition::PRED:
	    break;
	}
	s += predToChain(pC->Right(), depth+1);
    }
    return s;
}

Chain CegoQueryHelper::predToChain(CegoPredicate* pP, unsigned depth)
{
    Chain s;

    s += pP->toChain(0); 
        
    if (pP->getCondition())
    {
	s = condToChain(pP->getCondition(), depth+1);
    }
    else
    {
	for (unsigned i=0;i<depth;i++)
	    s+= Chain(" ");	
    }
    return s;    
}

void CegoQueryHelper::aggregateTuple(ListT<CegoField>& aggTuple, CegoExpr* pExpr)
{
    CegoAggregation **pAgg = pExpr->getAggregationList().First();
    
    while ( pAgg )
    {
	aggregateTuple(aggTuple, *pAgg);	
	pAgg = pExpr->getAggregationList().Next();
    }
}

void CegoQueryHelper::aggregateTuple(ListT<CegoField>& aggTuple, CegoAggregation* pAgg)
{    
    switch ( pAgg->getType() )
    {	
    case CegoAggregation::COUNT:
    {       	
	if ( pAgg->getFieldValue().getValue() == 0 )
	{
	    pAgg->setFieldValue( CegoFieldValue(LONG_TYPE, Chain("1")) );
	}
	else
	{
	    (*(((long long*)(pAgg->getFieldValue().getValue()))))++;			    
	}			
	break;
    }
    case CegoAggregation::SUM:
    case CegoAggregation::AVG:
    {
	CegoFieldValue fv;
	
	CegoExpr *pAE = pAgg->getExpr();
	
	if ( pAE )
	{
	    ListT<CegoField>* fl[2];
	    fl[0] = &aggTuple;
	    fl[1] = 0;

	    fv = pAE->evalFieldValue(fl, 0);
	}

	if ( fv.getType() == VARCHAR_TYPE )
	{
	    Chain msg = Chain("sum/avg not supported on datatype <") + CEGO_TYPE_MAP[ (unsigned) fv.getType()] + Chain(">");
	    throw Exception(EXLOC, msg);
	}
	
	if ( pAgg->getFieldValue().getValue() == 0 )
	{
	    pAgg->setFieldValue( fv.getLocalCopy() );
	}
	else
	{
	    // local copy via add 
	    pAgg->setFieldValue( pAgg->getFieldValue() + fv );
	}    		   
	break;
    }
    case CegoAggregation::MIN:
    {
	CegoFieldValue fv;
	CegoExpr *pAE = pAgg->getExpr();
	
	if ( pAE )
	{
	    ListT<CegoField>* fl[2];
	    fl[0] = &aggTuple;
	    fl[1] = 0;

	    fv = pAE->evalFieldValue(fl, 0);
	}
	
	if ( pAgg->getFieldValue().getValue() == 0 )
	{
	    pAgg->setFieldValue( fv.getLocalCopy() );
	}
	else
	{		
	    if ( (CegoFieldValue)pAgg->getFieldValue() > fv )
	    {
		pAgg->setFieldValue( fv.getLocalCopy() );
	    }
	}
	break;
    }	    
    case CegoAggregation::MAX:
    {
	CegoFieldValue fv;
	CegoExpr *pAE = pAgg->getExpr();
	
	if ( pAE )
	{
	    ListT<CegoField>* fl[2];
	    fl[0] = &aggTuple;
	    fl[1] = 0;

	    fv = pAE->evalFieldValue(fl, 0);
	}	
	
	if ( pAgg->getFieldValue().getValue() == 0 )
	{	    
	    pAgg->setFieldValue( fv.getLocalCopy() );
	}
	else
	{		
	    if ( (CegoFieldValue)pAgg->getFieldValue() < fv )
	    {		
		pAgg->setFieldValue( fv.getLocalCopy() );
	    }
	}
	
	break;
    }		
    }
}

void CegoQueryHelper::prepareFieldValue(CegoField* pFV, CegoFieldValue& fv, CegoTableManager* pTM, unsigned tabSetId)
{
    
    // first we check if the field is nullable and a value is given
    if ( pFV->isNullable() == false && fv.isNull() )
    {
	throw Exception(EXLOC, Chain("Invalid null value for attribute <") 
			+ pFV->getAttrName() 
			+ Chain("> in value list"));
    }

    if ( fv.getType() != NULL_TYPE && pFV->getType() != fv.getType() )	
    {
	if ( pFV->getType() == CLOB_TYPE && fv.getType() == VARCHAR_TYPE && pTM )
	    if ( string2Clob(fv, pTM, tabSetId) )
		return;

	if ( fv.castTo(pFV->getType(), pFV->getDim()) == false )
	{
	    throw Exception(EXLOC, Chain("Mismatched datatype <") 
			    + CEGO_TYPE_MAP[(unsigned)fv.getType()] 
			    + Chain("> for attribute ") + pFV->getAttrName() 
			    + ", expected <" 
			    + CEGO_TYPE_MAP[(unsigned)pFV->getType()] + ">");
	}
    }    
    
    if ( fv.getValue() != 0 )
    {
	if ( pFV->getLength() < fv.getLength() -1 ) 
	{	    
	    throw Exception(EXLOC, Chain("Value length for ") + pFV->getAttrName() + Chain(" exceeded ( max len is ") + Chain(pFV->getLength()) + Chain(")"));
	}
	
	if ( pFV->getType() == VARCHAR_TYPE  
	     && pFV->getLength() < fv.getLength() )
	{
	    Chain shrinkVal ( (char*) fv.getValue() );
	    fv = CegoFieldValue(VARCHAR_TYPE, shrinkVal.subChain(1, pFV->getLength()));
	}
	else if ( pFV->getType() == DATETIME_TYPE )
	{
	    long long dateVal;
	    memcpy(&dateVal, fv.getValue(), sizeof(long long));
	    if  (dateVal == 0 ) 
	    {
		Datetime n;
		long long dtval = n.asLong();
		memcpy(fv.getValue(), &dtval, sizeof(long long));  
	    }
	}
	else if ( pFV->getType() == BLOB_TYPE || pFV->getType() == CLOB_TYPE )
	{
	    PageIdType pageId;
	    memcpy(&pageId, fv.getValue(), sizeof(PageIdType));
	    
	    if ( pTM->getDBMng()->isClaimed(pageId, pTM->getLockHandler()))
	    {		    
		CegoBufferPage bp;
		pTM->getDBMng()->bufferFix(bp, tabSetId, pageId, CegoBufferPool::SYNC, pTM->getLockHandler());
		pTM->getDBMng()->bufferUnfix(bp, true, pTM->getLockHandler());
		
		if (  pFV->getType() == BLOB_TYPE && bp.getType() == CegoBufferPage::BLOB )
		{
		    // ok !
		}
		else if (  pFV->getType() == CLOB_TYPE && bp.getType() == CegoBufferPage::CLOB )
		{
		    // ok !
		}
		else
		{
		    throw Exception(EXLOC, Chain("Invalid lob type"));
		}		    
	    }
	}
	else if ( pFV->getType() == DECIMAL_TYPE )
	{
	    // for fixed values, we have to check the correct dimension
	    
	    Chain fixedVal = fv.valAsChain();
	    
	    unsigned long pos;
	    if ( fixedVal.posStr(Chain("."), pos) == false )
		throw Exception(EXLOC, Chain("Invalid decimal value <") + fixedVal + Chain(">"));
	    
	    unsigned dim = fixedVal.length() - pos - 1;
	    
	    if ( dim < pFV->getDim() )
	    {
		unsigned diff = pFV->getDim() - dim;
		while ( diff > 0 )
		{
		    fixedVal = fixedVal + Chain("0");
		    diff --;
		}
	    }
	    else if ( dim > pFV->getDim() )
	    {
		unsigned diff = dim - pFV->getDim();
		fixedVal = fixedVal.subChain(1, fixedVal.length() - ( diff + 1) );
	    }

	    fv = CegoFieldValue(DECIMAL_TYPE, fixedVal);
	}
    }
}

bool CegoQueryHelper::checkIndexForPredicate(unsigned tabSetId, CegoQueryManager* pGTM, CegoPredicate *pPred, ListT<CegoContentObject*>& coList)
{  
    CegoCondition* pC = pPred->getCondition();	
    if (pC)
    {
	if (pC->getCondType() == CegoCondition::AND)
	{
	    return checkIndexForPredicate(tabSetId, pGTM, pC->Left(), coList) || checkIndexForPredicate(tabSetId, pGTM, pC->Right(), coList);
	}
	else
	{
	    return false;
	}
    }
    else if ( pPred->getMode() == CegoPredicate::EXPRCOMP  || pPred->getMode() == CegoPredicate::IN )
    {

	SetT<Chain> tableRefSet = pPred->getTableRefSet();
	ListT<CegoAttrDesc*> attrRefList = pPred->getAttrRefList();
		
	if ( tableRefSet.Size() == 1 )
	{
	    Chain *pTableName = tableRefSet.First();
	    
	    ListT<CegoTableObject> idxList;
	    ListT<CegoBTreeObject> btreeList;
	    ListT<CegoKeyObject> keyList;
	    ListT<CegoCheckObject> checkList;
	    ListT<CegoTriggerObject> triggerList;
	    ListT<CegoAliasObject> aliasList;
	    unsigned numInvalid;

	    unsigned tsId;
	    Chain tabName;
	    CegoContentObject **pCO = coList.First();
	    bool found=false;
	    while ( pCO && ! found )
	    {		
		if ( (*pCO)->getName() == *pTableName || (*pCO)->getTabName() == *pTableName )
		{
		    // the table might be in a different tableset
		    tsId = (*pCO)->getTabSetId();
		    tabName = (*pCO)->getTabName();
		    found=true;

		}
		else
		{
		    pCO = coList.Next();
		}
	    }

	    // we just check index objects for appropriate physical objects ( e.g. join objects are not appropriate )
	    if ( found )
	    {		
		pGTM->getObjectListByTable(tsId, tabName, idxList, btreeList, keyList, checkList, triggerList, aliasList, numInvalid);

		ListT<CegoAttrAlias> aliasList;
		if ( (*pCO)->getType() == CegoObject::ALIAS )
		{		    
		    aliasList = ((CegoAliasObject*)*pCO)->getAliasList();
		}
		    		
		CegoBTreeObject *pBTO = btreeList.First();
		
		while ( pBTO )
		{
		    if ( pBTO->isValid() )
		    {
			CegoField *pIF = pBTO->getSchema().First();
			if ( pIF )
			{
			    CegoAttrDesc **pAttrDesc =  attrRefList.First();
			    while ( pAttrDesc )
			    {
				Chain attrName =  (*pAttrDesc)->getAttrName();
				
				CegoAttrAlias *pA = aliasList.First();
				bool found=false;
				while ( pA && ! found )
				{
				    if ( (*pAttrDesc)->getAttrName() == pA->getAliasName() )
				    {
					attrName =  pA->getAttrName();
					found = true;
				    }
				    else
				    {
					pA = aliasList.Next();
				    }
				}
				
				if ( attrName == pIF->getAttrName() )
				{
				    return true;
				}
				pAttrDesc =  attrRefList.Next();
			    }
			    
			    pIF = pBTO->getSchema().Next();
			}
		    }
		    pBTO = btreeList.Next();
		}		
	    }
	}
    }
    return false;
}

void CegoQueryHelper::encodeFL(const ListT<CegoField>& fvl, char* &pBufBase, unsigned &buflen)
{
    CegoField* pF = fvl.First();
    while (pF)
    {
	buflen += sizeof(CegoDataType); // datatype
	buflen += sizeof(unsigned); // datatype len
	buflen += sizeof(unsigned); // datatype dim
	buflen += sizeof(unsigned); // defaultvalue len

	if ( pF->getValue().getLength() > 0 )
	    buflen += pF->getValue().getLength();

	buflen += sizeof(char); // isNullable
	buflen += sizeof(unsigned); // attr length
	buflen += pF->getAttrName().length(); // attr

	pF = fvl.Next();
    }
    
    pBufBase = (char*) malloc(buflen);
    
    if (pBufBase == 0)
    {
	throw Exception(EXLOC, "malloc system error");
    }

    char *pBuf = pBufBase;

    pF = fvl.First();
    while (pF)
    {
	unsigned attrLength =  (unsigned)pF->getAttrName().length();
	CegoDataType dt = pF->getType();
		
	memcpy( pBuf, &dt, sizeof(CegoDataType));
	pBuf += sizeof(CegoDataType);

        unsigned dtlen = (unsigned)pF->getLength();
	
	memcpy( pBuf, &dtlen, sizeof(unsigned));
	pBuf += sizeof(unsigned);

	unsigned dim = pF->getDim();
	
	memcpy( pBuf, &dim, sizeof(unsigned));
	pBuf += sizeof(unsigned);

	unsigned deflen = pF->getValue().getLength();

	memcpy( pBuf, &deflen, sizeof(unsigned));
	pBuf += sizeof(unsigned);

	if ( deflen > 0 )
	{
	    memcpy( pBuf, pF->getValue().getValue(), deflen);
	    pBuf += deflen;
	}
	
	char isNullable = 0;
	if ( pF->isNullable() )
	    isNullable = 1;

	memcpy( pBuf, &isNullable, sizeof(char));
	pBuf += sizeof(char);
	
	memcpy( pBuf, &attrLength, sizeof(unsigned));
	pBuf += sizeof(unsigned);

	memcpy( pBuf, (char*)pF->getAttrName(), attrLength);
	pBuf += attrLength;

	pF = fvl.Next();
    }
}

void CegoQueryHelper::decodeFL(ListT<CegoField>& fvl, char* pc, unsigned len)
{
    char *pBase = pc;

    while (pc - pBase < len)
    {
	CegoDataType dt;
	memcpy(&dt, pc, sizeof(CegoDataType));
	pc += sizeof(CegoDataType);

	unsigned dtlen;
	memcpy( &dtlen, pc, sizeof(unsigned));
	pc += sizeof(unsigned);

	unsigned dim;
	memcpy( &dim, pc, sizeof(unsigned));
	pc += sizeof(unsigned);

	CegoFieldValue defVal;

	unsigned deflen;
	memcpy( &deflen, pc, sizeof(unsigned));
	pc += sizeof(unsigned);
	if ( deflen > 0 )
	{
	    defVal = CegoFieldValue(dt, pc, deflen, false);
	    pc += deflen;
	}

	char isNullable;
	memcpy(&isNullable, pc, sizeof(char));
	pc += sizeof(char);

	unsigned attrLength;
	memcpy( &attrLength, pc, sizeof(unsigned));
	pc += sizeof(unsigned);
	
	Chain attrName(pc, attrLength-1);
	pc += attrLength;

	Chain n;

	fvl.Insert(CegoField(n,n, attrName, dt, dtlen, dim, defVal, isNullable));		
    }
}

unsigned CegoQueryHelper::encodeFVL(unsigned long long tid, unsigned long long tastep, CegoTupleState ts, const ListT<CegoField>& fvl, char* &pBufBase, unsigned& buflen)
{
    ListT<CegoBlob> blobList;
    ListT<CegoClob> clobList;    
    return encodeFVL(tid, tastep, ts, fvl, blobList, clobList, pBufBase, buflen);
}

unsigned CegoQueryHelper::encodeFVL(unsigned long long tid, unsigned long long tastep, CegoTupleState ts, const ListT<CegoField>& fvl, const ListT<CegoBlob>& blobList, const ListT<CegoClob>& clobList, char* &pBufBase, unsigned& buflen)
{
    unsigned enclen = skipTupleHeader();

    unsigned blobIdx = 0;
    unsigned clobIdx = 0;
    
    CegoField* pF = fvl.First();
    while (pF)
    {
	unsigned l =  (unsigned)pF->getValue().getLength();
	CegoDataType dt = pF->getValue().getType();
	
	// force null type in case of fv length and value constraints 
	if ( l == 0 || pF->getValue().getValue() == 0 )
	    dt = NULL_TYPE;
		
	if ( dt != NULL_TYPE )
	{
	    enclen += sizeof(unsigned); // id
	    enclen += sizeof(CegoDataType);

	    if ( dt == BLOB_TYPE && blobList.Size() > 0)
	    {	
		enclen += sizeof(unsigned long long); // blobsize
		enclen += blobList[blobIdx].getSize();
		blobIdx++;
	    }
	    else if ( dt == CLOB_TYPE && clobList.Size() > 0)
	    {		
		enclen += sizeof(unsigned long long); // clobsize
		enclen += clobList[clobIdx].getSize();
		clobIdx++;
	    }
	    else
	    {
		if ( dt == VARCHAR_TYPE 
		     || dt == BIGINT_TYPE
		     || dt == DECIMAL_TYPE )
		{
		    enclen += sizeof(int);
		}
		
		enclen += pF->getValue().getLength();
	    }
	}
	pF = fvl.Next();
    }

    enclen += sizeof(unsigned); // terminating id

    if ( enclen > buflen )
    {
	if ( pBufBase != 0 )
	    free(pBufBase);
	pBufBase = (char*) malloc(enclen);
	buflen = enclen;
    }
    
    if (pBufBase == 0)
    {
	throw Exception(EXLOC, "malloc system error");	
    }

    char *pBuf = pBufBase;

    unsigned toff = encodeTupleHeader(tid, tastep, ts, pBuf);
    pBuf += toff;

    blobIdx = 0;
    clobIdx = 0;
    
    pF = fvl.First();
    while (pF)
    {
	unsigned id =  pF->getId();
	unsigned l =  (unsigned)pF->getValue().getLength();
	CegoDataType dt = pF->getValue().getType();

	// force null type in case of fv length and value constraints 
	if ( l == 0 || pF->getValue().getValue() == 0 )
	    dt = NULL_TYPE;
	
	if ( dt != NULL_TYPE )
	{
	    memcpy( pBuf, &id, sizeof(unsigned));
	    pBuf += sizeof(unsigned);
	    
	    memcpy( pBuf, &dt, sizeof(CegoDataType));
	    pBuf += sizeof(CegoDataType);

	    if ( dt == BLOB_TYPE && blobList.Size() > 0)
	    {
		unsigned long long blobSize = blobList[blobIdx].getSize();
		memcpy( pBuf, &blobSize, sizeof(unsigned long long));
		pBuf += sizeof(unsigned long long);
		memcpy( pBuf, blobList[blobIdx].getBufPtr(), blobList[blobIdx].getSize());
		pBuf += blobList[blobIdx].getSize();
		blobIdx++;
	    }
	    else if ( dt == CLOB_TYPE && clobList.Size() > 0)
	    {
		unsigned long long clobSize = clobList[clobIdx].getSize();
		memcpy( pBuf, &clobSize, sizeof(unsigned long long));
		pBuf += sizeof(unsigned long long);
		memcpy( pBuf, clobList[clobIdx].getBufPtr(), clobList[clobIdx].getSize());
		pBuf += clobList[clobIdx].getSize();
		clobIdx++;
	    }
	    else
	    {
		if ( dt == VARCHAR_TYPE 
		     || dt == BIGINT_TYPE 
		     || dt == DECIMAL_TYPE )
		{
		    memcpy( pBuf, &l, sizeof(unsigned));
		    pBuf += sizeof(unsigned);
		}

		memcpy( pBuf, pF->getValue().getValue(), l);	
		
		pBuf += l;
	    }
	}
	
	pF = fvl.Next();
    }

    unsigned termId=0;
    memcpy( pBuf, &termId, sizeof(unsigned));

    return enclen;
}

// for performance reasons, we also provide a method to just return the 
// tuple header len
unsigned CegoQueryHelper::skipTupleHeader()
{
    return sizeof(unsigned long long) + sizeof(unsigned long long) + sizeof(CegoTupleState);
}

unsigned CegoQueryHelper::encodeTupleHeader(unsigned long long tid, unsigned long long tastep, CegoTupleState ts, char* p)
{
    memcpy(p, &tid, sizeof(unsigned long long));
    p += sizeof(unsigned long long);
    memcpy(p, &tastep, sizeof(unsigned long long));
    p += sizeof(unsigned long long);
    memcpy(p, &ts, sizeof(CegoTupleState));
    
    return sizeof(unsigned long long) + sizeof(unsigned long long) + sizeof(CegoTupleState);
}

unsigned CegoQueryHelper::decodeTupleHeader(unsigned long long& tid, unsigned long long& tastep, CegoTupleState& ts, char* p)
{
    memcpy(&tid, p, sizeof(unsigned long long));

    char* ptastep = p + sizeof(unsigned long long);
    memcpy(&tastep, ptastep, sizeof(unsigned long long));
    
    char* pts = p + sizeof(unsigned long long) + sizeof(unsigned long long);
    memcpy(&ts, pts, sizeof(CegoTupleState));
	
    return sizeof(unsigned long long) + sizeof(unsigned long long) + sizeof(CegoTupleState);
}

void CegoQueryHelper::decodeFVL(ListT<CegoField>& fvl, char* pc, unsigned len)
{        
    char* pBase = pc;
    bool eot = false;

    CegoField* pF = fvl.First();
    
    while (pF && pc - pBase < len && eot == false)
    {
	unsigned id;     
	memcpy(&id, pc, sizeof(unsigned));
	
	if ( id > 0 )
	{	    
	    pc += sizeof(unsigned);
	    
	    CegoDataType dt;
	    memcpy(&dt, pc, sizeof(CegoDataType));
	    
	    pc += sizeof(CegoDataType);
	    
	    unsigned flen;
	    
	    if (dt == VARCHAR_TYPE
		|| dt == BIGINT_TYPE
		|| dt == DECIMAL_TYPE )
	    {
		memcpy(&flen, pc, sizeof(unsigned));
		pc += sizeof(unsigned);
	    }
	    else
	    {
		flen = CegoTypeConverter::getTypeLen(dt);	    
	    }
	    
	    if ( id >= pF->getId() )
            {
                while ( pF && id > pF->getId() )
		{
		    pF->setupNull();
		    pF=fvl.Next();
		}
                if ( pF && id == pF->getId() )
                {
		    pF->setupValue(dt, flen > 0 ? pc : 0, flen);		    
		    pF = fvl.Next();
               }
            }
	    
	    if ( flen > 0 )
	    {	    
		pc += flen;
	    }
	}
	else
	{
	    eot = true;
	}	    
    }

    while ( pF )
    {
	pF->setupNull();
	pF=fvl.Next();
    }
}

/* field list decoding with included blob decoding. This is used by the recovery manager for redo log recovery  */
void CegoQueryHelper::decodeFVL(ListT<CegoField>& fvl, ListT<CegoBlob>& blobList, ListT<CegoClob>& clobList, char* pc, unsigned len)
{    
    // make sure no field values are set
    CegoField* pF = fvl.First(); 
    while ( pF )
    {
	CegoFieldValue nullValue;
	pF->setValue(nullValue);
	pF = fvl.Next();	
    }

    char* pBase = pc;
    
    bool eot = false;
    while (pc - pBase < len && eot == false )
    {
	unsigned id;
	memcpy(&id, pc, sizeof(unsigned));

	if ( id > 0 )
	{
	    pc += sizeof(unsigned);
	    
	    CegoDataType dt;
	    memcpy(&dt, pc, sizeof(CegoDataType));
	    pc += sizeof(CegoDataType);
	    
	    unsigned flen=0;
	    unsigned long long blobSize=0;
	    unsigned long long clobSize=0;
	    
	    if (dt == VARCHAR_TYPE
		|| dt == BIGINT_TYPE
		|| dt == DECIMAL_TYPE )	    
	    {
		memcpy(&flen, pc, sizeof(unsigned));
		pc += sizeof(unsigned);
	    }
	    else if (dt == BLOB_TYPE )
	    {
		memcpy(&blobSize, pc, sizeof(unsigned long long));
		pc += sizeof(unsigned long long);
	    }
	    else if (dt == CLOB_TYPE )
	    {
		memcpy(&clobSize, pc, sizeof(unsigned long long));
		pc += sizeof(unsigned long long);
	    }
	    else
	    {	       
		 flen = CegoTypeConverter::getTypeLen(dt);
	    }
	    
	    bool found = false;
	    CegoField* pF = fvl.First(); 
	    while (pF && ! found )
	    {
		if (pF->getId() == id )
		{
		    if ( dt == BLOB_TYPE )
		    {
			CegoFieldValue fv = pF->getValue();
			fv.setType(dt);
			pF->setValue(fv);
			
			unsigned char *blobBuf = (unsigned char*)malloc(blobSize);
			memcpy(blobBuf, pc, blobSize);
			blobList.Insert( CegoBlob(0, blobBuf, blobSize) );
		    }
		    else if ( dt == CLOB_TYPE )
		    {
			CegoFieldValue fv = pF->getValue();
			fv.setType(dt);
			pF->setValue(fv);

			char *clobBuf = (char*)malloc(clobSize);
			memcpy(clobBuf, pc, clobSize);
			clobList.Insert( CegoClob(0, clobBuf, clobSize) );
		    }
		    else
		    {
			CegoFieldValue fv = pF->getValue();
			fv.setType(dt);			
			fv.setLength(flen);			
			if ( flen > 0)
			    fv.setValue(pc);
			else
			    fv.setValue(0);
			fv.setLocalCopy(false);
			
			pF->setValue(fv);
			pF->setId(id);						
		    }
		    found = true;
		}
		pF = fvl.Next();
	    }
	    
	    if ( blobSize > 0 )
	    {
		pc += blobSize;
	    }

	    if ( clobSize > 0 )
	    {
		pc += clobSize;
	    }
	    
	    if ( flen > 0 )
	    {
		pc += flen;
	    }
	}
	else
	{
	    eot = true;
	}
    }
}

void CegoQueryHelper::decodeNativeFVL(ListT<CegoFieldValue>& fvl, ListT<CegoBlob>& blobList, ListT<CegoClob>& clobList, char* pc, unsigned len)
{
    char* pBase = pc;

    bool eot = false;    
    while (pc - pBase < len && eot == false)
    {		    
	unsigned id;
	memcpy(&id, pc, sizeof(unsigned));

	if ( id > 0 )
	{       
	    pc += sizeof(unsigned);
	    
	    CegoDataType dt;
	    memcpy(&dt, pc, sizeof(CegoDataType));
	    
	    pc += sizeof(CegoDataType);
	    
	    unsigned flen=0;
	    unsigned long long blobSize=0;
	    unsigned long long clobSize=0;
	    
	    if (dt == VARCHAR_TYPE
		|| dt == BIGINT_TYPE
		|| dt == DECIMAL_TYPE )	    
	    {
		memcpy(&flen, pc, sizeof(unsigned));
		pc += sizeof(unsigned);
	    }
	    else if (dt == BLOB_TYPE )
	    {
		memcpy(&blobSize, pc, sizeof(unsigned long long));
		pc += sizeof(unsigned long long);
	    }
	    else if (dt == CLOB_TYPE )
	    {
		memcpy(&clobSize, pc, sizeof(unsigned long long));
		pc += sizeof(unsigned long long);
	    }
	    else
	    {		
		flen = CegoTypeConverter::getTypeLen(dt);
	    }
	    
	    if ( dt == BLOB_TYPE )
	    {
		CegoFieldValue fv(dt, Chain("[0]"));
		unsigned char *blobBuf = (unsigned char*)malloc(blobSize);
		memcpy(blobBuf, pc, blobSize);
		blobList.Insert( CegoBlob(0, blobBuf, blobSize) );		
		fvl.Insert(fv);
	    }
	    else if ( dt == CLOB_TYPE )
	    {
		CegoFieldValue fv(dt, Chain("[0]"));
		char *clobBuf = (char*)malloc(clobSize);
		memcpy(clobBuf, pc, clobSize);
		clobList.Insert( CegoClob(0, clobBuf, clobSize) );		
		fvl.Insert(fv);
	    }	    
	    else
	    {
		CegoFieldValue fv(dt, pc, flen);
		fvl.Insert(fv);
	    }
	    
	    if ( blobSize > 0 )
	    {
		pc += blobSize;
	    }
	    
	    if ( clobSize > 0 )
	    {
		pc += clobSize;
	    }

	    if ( flen > 0 )
	    {
		pc += flen;
	    }
	}   
	else
	{
	    eot = true;
	}
    }
}

void CegoQueryHelper::encodeUpdRec(const Chain& tableAlias,
				   CegoPredicate* pPred,
				   const ListT<CegoField>& updList,
				   const ListT<CegoExpr*>& exprList,
				   const ListT<CegoBlob>& blobList,
				   const ListT<CegoClob>& clobList,
				   bool returnOnFirst,
				   CegoProcBlock* pBlock,
				   char* &pBuf, unsigned &buflen)
{
    char* updBuf;
    unsigned updBufLen = 0;
    char* predBuf;
    unsigned predBufLen = 0;
    char* expBuf;
    unsigned expBufLen = 0;

    if ( pPred )
    {
	predBufLen = pPred->getEncodingLength(pBlock) + sizeof(char);
	predBuf = (char*)malloc( predBufLen );
	char* pP = predBuf;
	char c = 1;
	memcpy(pP, &c, sizeof(char));
	pP = pP + sizeof(char);
	pPred->encode(pP, pBlock);	
    }
    else
    {
	char c = 0;
	predBufLen = sizeof(char);
	predBuf = (char*)malloc( predBufLen);
	memcpy(predBuf, &c, sizeof(char));
    }

    encodeFL(updList, updBuf, updBufLen);

    expBufLen = 0;
    unsigned blobIdx=0;
    unsigned clobIdx=0;
    
    CegoExpr **pExpr = exprList.First();
    while ( pExpr )
    {       
	CegoFieldValue fv;
	if ( (*pExpr)->checkLob(fv, pBlock) )
	{
	    if ( fv.getType() == BLOB_TYPE  )
	    {
		expBufLen += sizeof(char); // lob indicator
		expBufLen += sizeof(unsigned long long); // blobsize
		expBufLen += blobList[blobIdx].getSize();
		blobIdx++;
	    }
	    else if ( fv.getType() == CLOB_TYPE )
	    {
		expBufLen += sizeof(char); // lob indicator
		expBufLen += sizeof(unsigned long long); // clobsize
		expBufLen += clobList[clobIdx].getSize();
		clobIdx++;
	    }
	}
	else	    
	{
	    expBufLen += sizeof(char); // lob indicator
	    expBufLen += (*pExpr)->getEncodingLength(pBlock);
	}
	pExpr = exprList.Next();
    }

    expBuf = (char*)malloc( expBufLen );
    char *pExpBuf = expBuf;
    
    blobIdx=0;
    clobIdx=0;

    pExpr = exprList.First();
    while ( pExpr )
    {
	    
	CegoFieldValue fv;
	if ( (*pExpr)->checkLob(fv, pBlock) )
	{
	    if ( fv.getType() == BLOB_TYPE  )
	    {
		char isLob=1;
		memcpy( pExpBuf, &isLob, sizeof(char));
		pExpBuf += sizeof(char);
		unsigned long long blobSize = blobList[blobIdx].getSize();
		memcpy( pExpBuf, &blobSize, sizeof(unsigned long long));
		pExpBuf += sizeof(unsigned long long);
		memcpy( pExpBuf, blobList[blobIdx].getBufPtr(), blobList[blobIdx].getSize());
		pExpBuf += blobList[blobIdx].getSize();
		blobIdx++;
	    }
	    else if ( fv.getType() == CLOB_TYPE )
	    {		
		char isLob=2;
		memcpy( pExpBuf, &isLob, sizeof(char));
		pExpBuf += sizeof(char);
		
		unsigned long long clobSize = clobList[clobIdx].getSize();
		memcpy( pExpBuf, &clobSize, sizeof(unsigned long long));
		pExpBuf += sizeof(unsigned long long);
		memcpy( pExpBuf, clobList[clobIdx].getBufPtr(), clobList[clobIdx].getSize());
		pExpBuf += clobList[clobIdx].getSize();
		clobIdx++;
	    }
	}
	else	    
	{
	    char isLob=0;
	    memcpy( pExpBuf, &isLob, sizeof(char));
	    pExpBuf += sizeof(char);

	    int len = (*pExpr)->getEncodingLength(pBlock);
	    (*pExpr)->encode(pExpBuf, pBlock);
	    pExpBuf += len;
	}

	pExpr = exprList.Next();
    }

    unsigned aliasLen = tableAlias.length();

    buflen = predBufLen
	+ sizeof(unsigned) + aliasLen
	+ sizeof(unsigned) + updBufLen
	+ sizeof(unsigned) + expBufLen
	+ sizeof(bool); // returnOnFirst

    pBuf = (char*)malloc(buflen);

    char* pBP = pBuf;

    memcpy(pBP, &aliasLen, sizeof(unsigned));
    pBP = pBP + sizeof(unsigned);

    memcpy( pBP, (char*)tableAlias, aliasLen);
    pBP = pBP + aliasLen;

    memcpy(pBP, predBuf, predBufLen);
    pBP = pBP + predBufLen;
    
    memcpy(pBP, &updBufLen, sizeof(unsigned));
    pBP = pBP + sizeof(unsigned);

    memcpy(pBP, updBuf, updBufLen);
    pBP = pBP + updBufLen;

    memcpy(pBP, &expBufLen, sizeof(unsigned));
    pBP = pBP + sizeof(unsigned);
    
    memcpy(pBP, expBuf, expBufLen);
    pBP = pBP + expBufLen;

    memcpy(pBP, &returnOnFirst, sizeof(bool));
    pBP = pBP + sizeof(bool);

    free ( predBuf );
    free ( updBuf );
    free ( expBuf );
}

void CegoQueryHelper::decodeUpdRec(Chain& tableAlias,
				   CegoPredicate* &pPred, 
				   ListT<CegoField>& updList, 
				   ListT<CegoExpr*>& exprList,
				   bool& returnOnFirst,
				   char* pBuf, unsigned buflen,
				   CegoQueryManager *pGTM, unsigned tabSetId)
{
    unsigned aliasLen;
    memcpy(&aliasLen, pBuf, sizeof(unsigned));
    pBuf += sizeof(unsigned);

    tableAlias = Chain(pBuf, aliasLen-1);
    pBuf += aliasLen;
    
    char c = 0;
    memcpy(&c, pBuf, sizeof(char));
    pBuf += sizeof(char);

    if ( c == 1 )
    {
	pPred = new CegoPredicate(pBuf);
	pBuf += pPred->getEncodingLength();
    }
    else
    {
	pPred = 0;
    }

    unsigned updBufLen;
    memcpy(&updBufLen, pBuf, sizeof(unsigned));
    pBuf += sizeof(unsigned);

    decodeFL(updList, pBuf, updBufLen);

    pBuf += updBufLen;

    unsigned expBufLen;
    memcpy(&expBufLen, pBuf, sizeof(unsigned));
    pBuf += sizeof(unsigned);

    int pos = 0;
    while ( pos < expBufLen  )
    {
	char isLob = 0;
	memcpy(&isLob, pBuf, sizeof(char));
	pBuf += sizeof(char);
	pos += sizeof(char);
	
	if ( isLob == 1 )
	{
	    unsigned long long blobSize;
	    memcpy(&blobSize, pBuf, sizeof(unsigned long long));

	    CegoFieldValue fv;
		    
	    if ( pGTM )
	    {
		pBuf += sizeof(unsigned long long);
		PageIdType pageId;
		pGTM->putBlobData(tabSetId, (unsigned char*)pBuf, blobSize, pageId);
		
		fv = CegoFieldValue(BLOB_TYPE, Chain("[") + Chain(pageId) + Chain("]"));
	    }
	    
	    CegoExpr *pExpr = new CegoExpr(new CegoTerm(new CegoFactor(fv)));
	    
	    exprList.Insert(pExpr);
	    
	    unsigned len = sizeof(unsigned long long) + blobSize;
	    pos += len;
	    pBuf += len;		

	}
	else if ( isLob == 2 )
	{
	    unsigned long long clobSize;
	    memcpy(&clobSize, pBuf, sizeof(unsigned long long));

	    CegoFieldValue fv;

	    if ( pGTM )
	    {
		pBuf += sizeof(unsigned long long);
		PageIdType pageId;
		pGTM->putClobData(tabSetId, pBuf, clobSize, pageId);
		
		fv = CegoFieldValue(CLOB_TYPE, Chain("[") + Chain(pageId) + Chain("]"));		
	    }

	    CegoExpr *pExpr = new CegoExpr(new CegoTerm(new CegoFactor(fv)));
	    
	    exprList.Insert(pExpr);
	    
	    unsigned len = sizeof(unsigned long long) + clobSize;
	    pos += len;
	    pBuf += len;
	}
	else
	{
	    CegoExpr *pExpr = new CegoExpr(pBuf);
	    
	    unsigned len = pExpr->getEncodingLength();
	    pos += len;
	    pBuf += len;
	    
	    exprList.Insert(pExpr);
	}
    }

    memcpy(&returnOnFirst, pBuf, sizeof(bool));
}

void CegoQueryHelper::encodeDelRec(const Chain& tableAlias,
				   CegoPredicate* pPred,
				   CegoProcBlock* pBlock,
				   char* &pBuf, unsigned &buflen)

{
    char* predBuf;
    unsigned predBufLen = 0;

    if ( pPred )
    {
	predBufLen = pPred->getEncodingLength(pBlock) + sizeof(char);
	predBuf = (char*)malloc( predBufLen );
	char* pP = predBuf;
	char c = 1;
	memcpy(pP, &c, sizeof(char));
	pP = pP + sizeof(char);

	pPred->encode(pP, pBlock);	
    }
    else
    {
	char c = 0;
	predBufLen = sizeof(char);
	predBuf = (char*)malloc( predBufLen);
	memcpy(predBuf, &c, sizeof(char));
    }

    unsigned aliasLen = (unsigned)tableAlias.length();

    buflen = predBufLen
	+ sizeof(unsigned) + aliasLen;
    
    pBuf = (char*)malloc(buflen);

    char* pBP = pBuf;

    memcpy(pBP, &aliasLen, sizeof(unsigned));
    pBP = pBP + sizeof(unsigned);

    memcpy( pBP, (char*)tableAlias, aliasLen);
    pBP = pBP + aliasLen;

    memcpy(pBP, predBuf, predBufLen);
    pBP = pBP + predBufLen;
    
    free ( predBuf );
}

void CegoQueryHelper::decodeDelRec(Chain& tableAlias,
				   CegoPredicate* &pPred,
				   char* pBuf, unsigned buflen)
{        
    unsigned aliasLen;
    memcpy(&aliasLen, pBuf, sizeof(unsigned));
    pBuf += sizeof(unsigned);
    
    tableAlias = Chain(pBuf, aliasLen-1);
    pBuf += aliasLen;
    
    char c = 0;
    memcpy(&c, pBuf, sizeof(char));
    pBuf += sizeof(char);

    if ( c == 1 )
    {
	pPred = new CegoPredicate(pBuf);
	pBuf += pPred->getEncodingLength();
    }
    else
    {
	pPred = 0;
    }
}

void CegoQueryHelper::createConjunctionList(CegoPredicate* pPred, ListT<CegoPredicate*>& conjunctionList)
{
    if (pPred)
    {
	CegoCondition* pC = pPred->getCondition();
	if (pC)
	{
	    if (pC->getCondType() == CegoCondition::AND)
	    {
		createConjunctionList(pC->Left(), conjunctionList);
		createConjunctionList(pC->Right(), conjunctionList);
	    }
	    else
	    {
		conjunctionList.Insert(pPred);
	    }
	}
	else
	{
	    conjunctionList.Insert(pPred);
	}
    }
}

bool CegoQueryHelper::string2Clob(CegoFieldValue& fv, CegoTableManager* pTM, unsigned tabSetId)
{
    if ( fv.getType() == VARCHAR_TYPE && pTM )
    {
	char* clobData = (char*)fv.getValue();
	unsigned long long clobSize = fv.getLength() - 1; // we don't take terminating zero byte
	
	PageIdType pageId;
	pTM->putClobData(tabSetId, clobData, clobSize, pageId);
	
	fv = CegoFieldValue(CLOB_TYPE, Chain("[") + Chain(pageId) + Chain("]"));

	return true;
    }
    return false;
}

Chain CegoQueryHelper::skipComment(Chain& line)
{
    Chain result;    
    unsigned pos=0;
    bool stringMode=false;
    bool commentFound=false;
    
    while ( pos < (unsigned)line.length() && commentFound == false)
    {
	if ( line[pos] == '\''  )
	{
	    if ( pos > 0 && line[pos-1] == '\\' )
	    {
		// ignore escaped sign
	    }
	    else
	    {
		if ( stringMode == false )
		    stringMode=true;
		else
		    stringMode=false;	    
	    }
	}
	
	if ( pos < (int)line.length() -2 )
	{
	    if ( line[pos] == '-' && line[pos+1] == '-' && stringMode == false)
	    {
		if ( pos > 1 )
		{
		    result = line.subChain(1, pos-1);
		}
		else
		{
		    result = Chain();
		}
		commentFound=true;
	    }
	}
	pos++;
    }

    if ( commentFound )
	return result.cutTrailing(" \t");
    else
	return line.cutTrailing(" \t");
}

bool CegoQueryHelper::hasOpenString(Chain& line)
{
    unsigned pos=0;
    bool stringMode=false;
    while ( pos < (int)line.length())
    {
	if ( line[pos] == '\'' )
	{
	    if ( pos > 0 && line[pos-1] == '\\' )
	    {
		// ignore escaped sign
	    }		
	    else
	    {
		if ( stringMode == false )
		    stringMode=true;
		else
		    stringMode=false;
	    }
	}
	pos++;
    }
    return stringMode;    
}

void CegoQueryHelper::localizeFL(ListT<CegoField>& returnList)
{   
    CegoField* pF = returnList.First(); 
    while ( pF )
    {
	CegoFieldValue fv = pF->getValue().getLocalCopy();
	pF->setValue(fv);
	pF = returnList.Next();	
    }
}

Chain CegoQueryHelper::sql2Regex(const Chain& sqlPattern)
{
    Chain regexPattern = sqlPattern;

    regexPattern.replaceAll(Chain("$"), Chain("[$]"), regexPattern);
    regexPattern.replaceAll(Chain("."), Chain("\\."), regexPattern);
    regexPattern.replaceAll(Chain("*"), Chain(".*"), regexPattern);
    regexPattern.replaceAll(Chain("%"), Chain(".*"), regexPattern);

    // rescue % sign match
    regexPattern.replaceAll(Chain("\\.*"), Chain("%"), regexPattern);
    
    regexPattern.replaceAll(Chain("_"), Chain("."), regexPattern);

    return Chain("^") + regexPattern + Chain("$");
}

void CegoQueryHelper::mapAliasSchema(ListT<CegoField>& schema, const ListT<CegoAttrAlias>& aliasList)
{
    CegoField *pF = schema.First();
    while ( pF )
    {
	CegoAttrAlias *pA = aliasList.Find( CegoAttrAlias(pF->getAttrName()));
	if ( pA )
	{
	    pF->setAttrName( pA->getAttrName());
	}
	pF = schema.Next();				
    }
}

void CegoQueryHelper::mapAliasPredicate(CegoPredicate* pPred, const Chain& tableAlias, const ListT<CegoAttrAlias>& aliasList)
{    
    ListT<CegoAttrDesc*> attrList = pPred->getAttrRefList();
    CegoAttrDesc **pAD = attrList.First();
    while ( pAD )
    {
	if ( (*pAD)->getTableName() == tableAlias || (*pAD)->getTableName() == Chain() )
	{
	    CegoAttrAlias *pA = aliasList.Find( CegoAttrAlias( (*pAD)->getAttrName() ) );
	    if ( pA )
	    {
		(*pAD)->setAttrName( pA->getAttrName() );
	    }
	}
	pAD = attrList.Next();
    }
}

CegoAttrCond CegoQueryHelper::mapAttrCond(const CegoAttrCond& attrCond, CegoAliasObject* pAO)
{
    CegoAttrCond mapCond;
    
    CegoAttrComp *pAC = attrCond.getAttrCompSet().First();
    while ( pAC )
    {
	CegoAttrComp mapComp = *pAC;

	CegoAttrAlias* pAL = pAO->getAliasList().Find(CegoAttrAlias(pAC->getAttrName()));

	if ( pAL )
	{
	    if ( pAC->getTableName() == pAO->getTabAlias()
		 && pAC->getAttrName() == pAL->getAliasName() )
	    {	    
		mapComp.setTableName(pAO->getTabName()); 	
		mapComp.setAttrName(pAL->getAttrName());
	    }
	    
	    // map attribute description 1
	    if ( pAC->getAttrDesc().getTableName() == pAO->getTabAlias()
		 && pAC->getAttrDesc().getAttrName() == pAL->getAliasName())
		mapComp.setAttrDesc( CegoAttrDesc(pAO->getTabName(), pAC->getAttrName()));
	    
	    // map attribute description 2
	    if ( pAC->getAttrDesc2().getTableName() == pAO->getTabAlias()
		 && pAC->getAttrDesc2().getAttrName() == pAL->getAliasName())
		mapComp.setAttrDesc2( CegoAttrDesc(pAO->getTabName(), pAC->getAttrName()));
	    	
	    mapCond.add(mapComp);
	}
	else
	{
	    throw Exception(EXLOC, Chain("Cannot map from alias attribute ") + pAC->getAttrName());
	}
	pAC = attrCond.getAttrCompSet().Next();
    }
    return mapCond;
}

void CegoQueryHelper::mapFLA(ListT<CegoField>* pFLAmap, ListT<CegoField>** pFLA,
			     unsigned offset, unsigned size, CegoAliasObject* pAO)
{
    pFLAmap->Empty();
	
    CegoField *pF = pFLA[offset]->First();

    while ( pF )
    {
	CegoAttrAlias *pAF = pAO->getAliasList().Find( pF->getAttrName() );	
	
	if  ( pAF  )
	{
	    CegoField f(pAO->getTabName(), pAF->getAttrName());
	    f.setId(pF->getId());
	    pFLAmap->Insert(f);
	}
	else
	{
	    // alias defintion might be a subset of the target table
	    // throw Exception(EXLOC, Chain("Cannot map to alias attribute ") + pF->getAttrName());
	}
	pF = pFLA[offset]->Next();
    }
}

void CegoQueryHelper::propFLA(ListT<CegoField>* pFLAmap, ListT<CegoField>** pFLA, unsigned offset, unsigned size, CegoAliasObject* pAO)
{
    pFLA[offset]->Empty();
    
    CegoAttrAlias *pAF = pAO->getAliasList().First();
    
    while ( pAF )
    {
	CegoField *pF = pFLAmap->Find( CegoField(pAO->getTabName(), pAF->getAttrName() ) );
	
	if  ( pF  )
	{
	    CegoField f(pAO->getTabAlias(), pAF->getAliasName());
	    f.setValue( pF->getValue() );
	    pFLA[offset]->Insert(f);
	}
	pAF = pAO->getAliasList().Next();
    }
}

unsigned CegoQueryHelper::maxFieldSize(CegoField *pF)
{
    unsigned maxLen = 0;
    
    switch ( pF->getType() )
    {
    case INT_TYPE:
    {
	maxLen = max(pF->getAttrName().length(), 
		     pF->getTableAlias().length(), 
		     pF->getTableName().length(),
		     MAX_INT_LEN);
	break;
    }
    case LONG_TYPE:
    {
	maxLen = max(pF->getAttrName().length(), 
		     pF->getTableAlias().length(), 
		     pF->getTableName().length(),
		     MAX_LONG_LEN);
	break;
    }
    case VARCHAR_TYPE:
    {
	unsigned l = pF->getLength();
	if ( l < MAX_NULL_LEN )
	    l = MAX_NULL_LEN;
	
	maxLen = max(pF->getAttrName().length(), 
		     pF->getTableAlias().length(), 
		     pF->getTableName().length(),
		     l);
	break;
    }
    case BOOL_TYPE:
    {
	maxLen = max(pF->getAttrName().length(), 
		     pF->getTableAlias().length(), 
		     pF->getTableName().length(),
		     MAX_BOOL_LEN);
	break;
    }
    case DATETIME_TYPE:
    {
	maxLen = max(pF->getAttrName().length(), 
		     pF->getTableAlias().length(), 
		     pF->getTableName().length(),
		     __dateLength);
	break;
    }
    case FLOAT_TYPE:
    {
	maxLen = max(pF->getAttrName().length(), 
		     pF->getTableAlias().length(), 
		     pF->getTableName().length(),
		     MAX_FLOAT_LEN);
	break;
    }
    case DOUBLE_TYPE:
    {
	maxLen = max(pF->getAttrName().length(), 
		     pF->getTableAlias().length(), 
		     pF->getTableName().length(),
		     MAX_DOUBLE_LEN);
	break;
    }
    case BIGINT_TYPE:
    {
	unsigned l = pF->getLength();
	if ( l < MAX_NULL_LEN )
	    l = MAX_NULL_LEN;

	maxLen = max(pF->getAttrName().length(), 
		     pF->getTableAlias().length(), 
		     pF->getTableName().length(),
		     l);
	break;
    }
    case SMALLINT_TYPE:
    {
	maxLen = max(pF->getAttrName().length(), 
		     pF->getTableAlias().length(), 
		     pF->getTableName().length(),
		     MAX_SMALLINT_LEN);
	break;
    }
    case TINYINT_TYPE:
    {
	maxLen = max(pF->getAttrName().length(), 
		     pF->getTableAlias().length(), 
		     pF->getTableName().length(),
		     MAX_TINYINT_LEN);
	break;
    }
    case DECIMAL_TYPE:
    {
	unsigned l = pF->getLength();
	if ( l < MAX_NULL_LEN )
	    l = MAX_NULL_LEN;
	
	maxLen = max(pF->getAttrName().length(), 
		     pF->getTableAlias().length(), 
		     pF->getTableName().length(),
		     l);
	break;
    }
    case BLOB_TYPE:
    case CLOB_TYPE:
    {
	maxLen = max(pF->getAttrName().length(), 
		     pF->getTableAlias().length(), 
		     pF->getTableName().length(),
		     MAX_BLOB_LEN);
	break;
    }
    case NULL_TYPE:
    {
	maxLen = max(pF->getAttrName().length(), 
		     pF->getTableAlias().length(), 
		     pF->getTableName().length(),
		     MAX_NULL_LEN);
	break;
	
    }
    case PAGEID_TYPE:
    {
	throw Exception(EXLOC, Chain("Cannot handle pageid type")); 
    }
    default:
    {
	throw Exception(EXLOC, Chain("Unknown datatype ") + Chain(pF->getType())); 
    }
    }
    return maxLen;    
}

unsigned CegoQueryHelper::max(unsigned i1, unsigned i2, unsigned i3, unsigned i4)
{
    unsigned c1 =  i1 < i2 ? i2 : i1 ;
    unsigned c2 =  i3 < i4 ? i4 : i3 ;
    return c1 < c2 ? c2 : c1 ;
}
