///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoFunction.cc
// ---------------
// Cego internal sql function implementation
//     
// Design and Implementation by Bjoern Lemke
//     
// (C)opyright 2000-2025 Bjoern Lemke
//
// IMPLEMENTATION MODULE
//
// Class: CegoFunction
// 
// Description: All internal SQL database functions
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

// LFC INCLUDES
#include <lfcbase/Datetime.h>
#include <lfcbase/Tokenizer.h>

// CEGO INCLUDES
#include "CegoFunction.h"
#include "CegoExpr.h"
#include "CegoQueryManager.h"
#include "CegoXMLdef.h"
#include "CegoDatabaseFormater.h"
#include "CegoProcedure.h"
#include "CegoAction.h"
#include "CegoTypeConverter.h"
#include "CegoReplacer.h"

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

CegoFunction::CegoFunction(CegoFunction::FunctionType type)
{
    _pTabMng = 0;
    _type = type;
}

CegoFunction::CegoFunction(CegoFunction::FunctionType type, ListT<CegoExpr*>& exprList)
{
    _pTabMng = 0;
    _exprList = exprList;
    _type = type;
}

CegoFunction::CegoFunction(char* buf)
{
    decode(buf);
    _pTabMng = 0;
    _tabSetId = 0;
    _pProc = 0;
}

CegoFunction::CegoFunction(CegoQueryManager* pTabMng, unsigned tabSetId, CegoFunction::FunctionType type)
{
    _pTabMng = pTabMng;
    _tabSetId = tabSetId;
    _type = type;
}

CegoFunction::CegoFunction(CegoQueryManager* pTabMng, unsigned tabSetId, const Chain& funcName, ListT<CegoExpr*>& exprList)
{
    _pTabMng = pTabMng;
    _exprList = exprList;
    _funcName = funcName;
    _tabSetId = tabSetId;
    _pProc = 0;
    _type = CegoFunction::USERDEFINED;
}

CegoFunction::~CegoFunction()
{
    cleanUp();
    
    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	delete (*pExpr);
	pExpr = _exprList.Next();
    }
}
    
void CegoFunction::cleanUp()
{
    try
    {	
	CegoExpr** pExpr = _exprList.First();
	while ( pExpr )
	{
	    (*pExpr)->cleanUp();
	    pExpr = _exprList.Next();
	}
	
	if ( _type == CegoFunction::USERDEFINED && _pProc )
	{
	    // cout << "Unusing user procedure .." << _pProc << " " << _funcName << endl;
	    _pTabMng->getDBMng()->unuseObject(_tabSetId, _funcName, CegoObject::PROCEDURE);
	    _pProc->cleanUp();
	    _pProc = 0;
	}
    }
    catch ( Exception e )
    {
	// ignored
    }
}

void CegoFunction::setQueryManager(CegoQueryManager* pTabMng)
{
    _pTabMng = pTabMng;
    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	(*pExpr)->setQueryManager(pTabMng);
	pExpr = _exprList.Next();
    }
}

void CegoFunction::setTabSetId(unsigned tabSetId)
{
    _tabSetId = tabSetId;
    
    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	(*pExpr)->setTabSetId(tabSetId);
	pExpr = _exprList.Next();
    }
}

unsigned CegoFunction::getTabSetId() const
{
    return _tabSetId;
}

Chain CegoFunction::getName() const
{
    Chain funcString;

    switch (_type)
    {
    case CegoFunction::INT2ASC:
    {
	funcString = Chain("int2asc");
	break;	
    }
    case CegoFunction::ASC2INT:
    {
	funcString = Chain("asc2int");
	break;	
    }
    case CegoFunction::TRIM:
    {
	funcString = Chain("trim");
	break;	
    }
    case CegoFunction::RTRIM:
    {
	funcString = Chain("rtrim");
	break;	
    }
    case CegoFunction::LTRIM:
    {
	funcString = Chain("ltrim");
	break;	
    }
    case CegoFunction::ROUND:
    {
	funcString = Chain("round");
	break;	
    }
    case CegoFunction::TRUNC:
    {
	funcString = Chain("trunc");
	break;	
    }
    case CegoFunction::SCANDATE:
    {
	funcString = Chain("scandate");
	break;	
    }
    case CegoFunction::DATE2STR:
    {
	funcString = Chain("date2str");
	break;	
    }
    case CegoFunction::DATE2LONG:
    {
	funcString = Chain("date2long");
	break;	
    }
    case CegoFunction::LONG2DATE:
    {
	funcString = Chain("long2date");
	break;	
    }
    case CegoFunction::NEWDATE:
    {
	funcString = Chain("newdate");
	break;	
    }
    case CegoFunction::LOWER:
    {
	funcString = Chain("lower");
	break;	
    }
    case CegoFunction::UPPER:
    {
	funcString = Chain("upper");
	break;	
    }
    case CegoFunction::LEFT:
    {
	funcString = Chain("left");
	break;	
    }
    case CegoFunction::RIGHT:
    {
	funcString = Chain("right");
	break;	
    }
    case CegoFunction::SUBSTR:
    {
	funcString = Chain("substr");
	break;	
    }
    case CegoFunction::GETPOS:
    {
	funcString = Chain("getpos");
	break;		
    }
    case CegoFunction::STR2INT:
    {
	funcString = Chain("str2int");
	break;		
    }
    case CegoFunction::STR2LONG:
    {
	funcString = Chain("str2long");
	break;		
    }
    case CegoFunction::RANDSTR:
    {
	funcString = Chain("randstr");
	break;		
    }
    case CegoFunction::RANDINT:
    {
	funcString = Chain("randint");
	break;		
    }
    case CegoFunction::MOD:
    {
	funcString = Chain("mod");
	break;		
    }
    case CegoFunction::LMOD:
    {
	funcString = Chain("lmod");
	break;		
    }
    case CegoFunction::DIV:
    {
	funcString = Chain("div");
	break;		
    }
    case CegoFunction::LDIV:
    {
	funcString = Chain("ldiv");
	break;		
    }
    case CegoFunction::POWER:
    {
	funcString = Chain("power");
	break;		
    }
    case CegoFunction::BITAND:
    {
	funcString = Chain("bitand");
	break;		
    }
    case CegoFunction::BITOR:
    {
	funcString = Chain("bitor");
	break;		
    }
    case CegoFunction::BITXOR:
    {
	funcString = Chain("bitxor");
	break;		
    }
    case CegoFunction::BLOBSIZE:
    {
	funcString = Chain("blobsize");
	break;		
    }
    case CegoFunction::BLOBREF:
    {
	funcString = Chain("blobref");
	break;		
    }
    case CegoFunction::CLOBSIZE:
    {
	funcString = Chain("clobsize");
	break;		
    }
    case CegoFunction::CLOBREF:
    {
	funcString = Chain("clobref");
	break;		
    }
    case CegoFunction::CLOB2STR:
    {
	funcString = Chain("clob2str");
	break;		
    }
    case CegoFunction::REPLACE:
    {
	funcString = Chain("replace");
	break;	
    }
    case CegoFunction::REGMATCH:
    {
	funcString = Chain("regmatch");
	break;	
    }
    case CegoFunction::LENGTH:
    {
	funcString = Chain("length");
	break;	
    }
    case CegoFunction::USERDEFINED:
    {
	funcString = _funcName;
	break;	
    }
    case CegoFunction::NEXTCOUNT:
    {
	funcString = Chain("nextcount");
	break;	
    }
    case CegoFunction::SETCOUNT:
    {
	funcString = Chain("setcount");
	break;	
    }
    case CegoFunction::GETCOUNT:
    {
	funcString = Chain("getcount");
	break;	
    }
    }
    return funcString;
}

CegoDataType CegoFunction::getReturnType()
{
    switch ( _type )
    {
    case INT2ASC:
    case TRIM:
    case LTRIM:
    case RTRIM:
    case DATE2STR:
    case LOWER:
    case UPPER:
    case LEFT:
    case RIGHT:
    case SUBSTR:
    case REPLACE:
    case REGMATCH:
    case RANDSTR:
    case CLOB2STR:
	return VARCHAR_TYPE;
    case ASC2INT:
    case ROUND:
    case GETPOS:
    case LENGTH:
    case TRUNC:
    case STR2INT:
    case RANDINT:
    case MOD:
    case DIV:
    case POWER:
    case BITAND:
    case BITOR:
    case BITXOR:
	return INT_TYPE;
    case SCANDATE:
    case LONG2DATE:
    case NEWDATE:
	return DATETIME_TYPE;
    case STR2LONG:
    case BLOBSIZE:
    case BLOBREF:
    case CLOBSIZE:
    case CLOBREF:
    case NEXTCOUNT:
    case SETCOUNT:
    case GETCOUNT:
    case LMOD:
    case LDIV:
    case DATE2LONG:
	return LONG_TYPE;
    default:
    // case USERDEFINED:
    {
	if ( _pTabMng == 0 )
	    throw Exception(EXLOC, "No valid table manager set up");

	CegoDataType returnType;
		
	if ( _pProc )
	{
	    returnType = _pProc->getReturnType();
	    return returnType;
	}
	
	if ( _pTabMng->isGraceMode()
	     &&  _pTabMng->getDBMng()->objectExists(_tabSetId, _funcName, CegoObject::PROCEDURE) == false )
	    return NULL_TYPE;

	_pTabMng->getDBMng()->useObject(_tabSetId, _funcName, CegoObject::PROCEDURE, CegoDatabaseManager::SHARED, _pTabMng);
	
	try 
	{	    
	    _pProc = _pTabMng->getProcedure(_tabSetId, _funcName);
	    returnType = _pProc->getReturnType();	  	    
	}
	catch ( Exception e )
	{
	    _pTabMng->getDBMng()->unuseObject(_tabSetId, _funcName, CegoObject::PROCEDURE);
	    throw Exception(EXLOC, Chain("Cannot get user function return type"), e);
	}

	return returnType;	
    }
    }
}

unsigned CegoFunction::getReturnTypeLen(const ListT<CegoField>& fl)
{
    switch ( _type )
    {
    case INT2ASC:
    {
	return 1;
    }
    case ASC2INT:
    {
	return sizeof(int);
    }
    case RANDSTR:
    {
	CegoExpr** pExpr = _exprList.First();
	if ( pExpr )
	{
	    if ( (*pExpr)->checkConst() )
		return (*pExpr)->evalFieldValue(0,0).asInteger();
	    return RETVAL_LEN;
	}
	return 0;
    }		
    case DATE2STR:
    {
	return 20;
    }
    case LEFT:
    case RIGHT:
    {
	CegoExpr** pSourceExpr = _exprList.First();
	CegoExpr** pLengthExpr = _exprList.Next();
	if ( pLengthExpr )
	{
	    if ( (*pLengthExpr)->checkConst() )	    
		return (*pLengthExpr)->evalFieldValue(0,0).asInteger();
	    else
		return (*pSourceExpr)->evalField(fl).getLength();	    
	}
	return 0;
    }
    case SUBSTR:
    {
	CegoExpr** pSourceExpr = _exprList.First();
	// CegoExpr** pOffsetExpr =
	_exprList.Next(); // not used
	CegoExpr** pLengthExpr = _exprList.Next();
	if ( pLengthExpr )
	{	    
	    if ( (*pLengthExpr)->checkConst() )	    
		return (*pLengthExpr)->evalFieldValue(0,0).asInteger();
	    else
		return (*pSourceExpr)->evalField(fl).getLength();
	}
	
	return 0;
    }
    case CLOB2STR:
    {
	return CLOB_FORMAT_LEN;
    }
    case LTRIM:
    case RTRIM:
    case TRIM:
    case LOWER:
    case UPPER:
    {
	CegoExpr** pExpr = _exprList.First();
	if ( pExpr )
	{
	    return (*pExpr)->evalField(fl).getLength();
	}
	return 0;
    }
    case REPLACE:
    {
	CegoExpr** pExpr = _exprList.First();
	return (*pExpr)->evalField(fl).getLength();
    }
    case REGMATCH:
    {
	CegoExpr** pExpr = _exprList.First();
	return (*pExpr)->evalField(fl).getLength();
    }
    case ROUND:
    case GETPOS:
    case LENGTH:
    case TRUNC:
    case STR2INT:
    case RANDINT:
    case MOD:
    case DIV:
    case POWER:
    case BITAND:
    case BITOR:
    case BITXOR:
	return sizeof(int);
    case STR2LONG:
    case BLOBSIZE:
    case BLOBREF:
    case CLOBSIZE:
    case CLOBREF:
    case NEXTCOUNT:
    case SETCOUNT:
    case GETCOUNT:
    case LMOD:
    case LDIV:
    case SCANDATE:
    case DATE2LONG:
    case LONG2DATE:
    case NEWDATE:
	return sizeof(long long);
    default:
    // case USERDEFINED:
    {
	if ( _pTabMng == 0 )
	    throw Exception(EXLOC, "No valid table manager set up");

	unsigned returnTypeLen;

	if ( _pProc )
	{
	    returnTypeLen = _pProc->getReturnTypeLen();
	    return returnTypeLen;
	}
	
	if ( _pTabMng->isGraceMode()
	     &&  _pTabMng->getDBMng()->objectExists(_tabSetId, _funcName, CegoObject::PROCEDURE) == false )
	    return 0;

	_pTabMng->getDBMng()->useObject(_tabSetId, _funcName, CegoObject::PROCEDURE, CegoDatabaseManager::SHARED, _pTabMng);
	
	try 
	{	    
	    _pProc = _pTabMng->getProcedure(_tabSetId, _funcName);	    
	    returnTypeLen = _pProc->getReturnTypeLen();	  	    
	}
	catch ( Exception e )
	{
	    _pTabMng->getDBMng()->unuseObject(_tabSetId, _funcName, CegoObject::PROCEDURE);
	    throw Exception(EXLOC, Chain("Cannot get user function return type length"), e);
	}

	return returnTypeLen;	
    }
    }
}

unsigned CegoFunction::getReturnTypeDim()
{
    if ( _type == USERDEFINED )
    {
	if ( _pTabMng == 0 )
	    throw Exception(EXLOC, "No valid table manager set up");
	
	unsigned returnTypeDim;

	if ( _pProc )
	{
	    returnTypeDim = _pProc->getReturnTypeDim();
	    return returnTypeDim;
	}
	
	if ( _pTabMng->isGraceMode()
	     &&  _pTabMng->getDBMng()->objectExists(_tabSetId, _funcName, CegoObject::PROCEDURE) == false )
	    return 0;

	_pTabMng->getDBMng()->useObject(_tabSetId, _funcName, CegoObject::PROCEDURE, CegoDatabaseManager::SHARED, _pTabMng);
	
	try 
	{	    
	    _pProc = _pTabMng->getProcedure(_tabSetId, _funcName);	    
	    returnTypeDim = _pProc->getReturnTypeDim();	  	    
	}
	catch ( Exception e )
	{
	    _pTabMng->getDBMng()->unuseObject(_tabSetId, _funcName, CegoObject::PROCEDURE);
	    throw Exception(EXLOC, Chain("Cannot get user function return type dim"), e);
	}

	return returnTypeDim;	
    }
    return 0;
}


const CegoFunction::FunctionType CegoFunction::getType() const
{
    return _type;
}

void CegoFunction::setExprList(ListT<CegoExpr*>& exprList)
{    
    if ( _type == INT2ASC && exprList.Size() != 1)
	throw Exception(EXLOC, Chain("Invalid parameter count for int2asc function"));
    if ( _type == ASC2INT && exprList.Size() != 1)
	throw Exception(EXLOC, Chain("Invalid parameter count for asc2int function"));
    if ( _type == TRIM && exprList.Size() != 2)
	throw Exception(EXLOC, Chain("Invalid parameter count for trim function"));
    if ( _type == LTRIM && exprList.Size() != 2)
	throw Exception(EXLOC, Chain("Invalid parameter count for ltrim function"));
    if ( _type == RTRIM && exprList.Size() != 2)
	throw Exception(EXLOC, Chain("Invalid parameter count for rtrim function"));
    if ( _type == ROUND && ( exprList.Size() < 1 || exprList.Size() > 2) )
	throw Exception(EXLOC, Chain("Invalid parameter count for round function"));
    if ( _type == SCANDATE && exprList.Size() != 2)
	throw Exception(EXLOC, Chain("Invalid parameter count for scandate function"));
    if ( _type == DATE2STR && exprList.Size() != 2)
	throw Exception(EXLOC, Chain("Invalid parameter count for date2str function"));
    if ( _type == DATE2LONG && exprList.Size() != 1)
	throw Exception(EXLOC, Chain("Invalid parameter count for date2long function"));
    if ( _type == LONG2DATE && exprList.Size() != 1)
	throw Exception(EXLOC, Chain("Invalid parameter count for long2date function"));
    if ( _type == NEWDATE && exprList.Size() > 6 )
	throw Exception(EXLOC, Chain("Invalid parameter count for newdate function"));
    if ( _type == LOWER && exprList.Size() != 1)
	throw Exception(EXLOC, Chain("Invalid parameter count for lower function"));
    if ( _type == UPPER && exprList.Size() != 1)
	throw Exception(EXLOC, Chain("Invalid parameter count for upper function"));
    if ( _type == LEFT && exprList.Size() != 2)
	throw Exception(EXLOC, Chain("Invalid parameter count for left function"));
    if ( _type == RIGHT && exprList.Size() != 2)
	throw Exception(EXLOC, Chain("Invalid parameter count for right function"));
    if ( _type == GETPOS && ( exprList.Size() < 2 || exprList.Size() > 4 ) )
	throw Exception(EXLOC, Chain("Invalid parameter count for getpos function"));
    if ( _type == SUBSTR && ( exprList.Size() < 2 || exprList.Size() > 3 ) )
	throw Exception(EXLOC, Chain("Invalid parameter count for substr function"));
    if ( _type == REPLACE && exprList.Size() != 3)
	throw Exception(EXLOC, Chain("Invalid parameter count for replace function"));
    if ( _type == REGMATCH && ( exprList.Size() != 3 && exprList.Size() != 4 ) )
	 throw Exception(EXLOC, Chain("Invalid parameter count for regmatch function"));
    if ( _type == LENGTH && exprList.Size() != 1)
	throw Exception(EXLOC, Chain("Invalid parameter count for length function"));
    if ( _type == TRUNC && exprList.Size() != 1)
	throw Exception(EXLOC, Chain("Invalid parameter count for trunc function"));
    if ( _type == STR2INT && exprList.Size() != 1)
	throw Exception(EXLOC, Chain("Invalid parameter count for str2int function"));
    if ( _type == STR2LONG && exprList.Size() != 1)
	throw Exception(EXLOC, "Invalid parameter count for str2long function");
    if ( _type == RANDSTR && exprList.Size() != 1)
	throw Exception(EXLOC, "Invalid parameter count for randstr function");
    if ( _type == RANDINT && exprList.Size() != 1)
	throw Exception(EXLOC, "Invalid parameter count for randint function");
    if ( _type == MOD && exprList.Size() != 2)
	throw Exception(EXLOC, "Invalid parameter count for mod function");
    if ( _type == DIV && exprList.Size() != 2)
	throw Exception(EXLOC, "Invalid parameter count for div function");
    if ( _type == LMOD && exprList.Size() != 2)
	throw Exception(EXLOC, "Invalid parameter count for lmod function");
    if ( _type == LDIV && exprList.Size() != 2)
	throw Exception(EXLOC, "Invalid parameter count for ldiv function");
    if ( _type == POWER && exprList.Size() != 2)
	throw Exception(EXLOC, "Invalid parameter count for power function");
    if ( _type == BITAND && exprList.Size() != 2)
	throw Exception(EXLOC, "Invalid parameter count for bitand function");
    if ( _type == BITOR && exprList.Size() != 2)
	throw Exception(EXLOC, "Invalid parameter count for bitor function");
    if ( _type == BITXOR && exprList.Size() != 2)
	throw Exception(EXLOC, "Invalid parameter count for bitxor function");
    if ( _type == BLOBSIZE && exprList.Size() != 1)
	throw Exception(EXLOC, "Invalid parameter count for blobsize function");
    if ( _type == BLOBREF && exprList.Size() != 1)
	throw Exception(EXLOC, "Invalid parameter count for blobref function");
    if ( _type == CLOBSIZE && exprList.Size() != 1)
	throw Exception(EXLOC, "Invalid parameter count for clobsize function");
    if ( _type == CLOBREF && exprList.Size() != 1)
	throw Exception(EXLOC, "Invalid parameter count for clobref function");
    if ( _type == CLOB2STR && exprList.Size() != 1)
	throw Exception(EXLOC, "Invalid parameter count for clob2str function");

    _exprList = exprList;
}

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

void CegoFunction::getFieldList(ListT<CegoField>& fl, ListT<CegoField>** pFLA) const
{
    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	(*pExpr)->getFieldList(fl, pFLA);
	pExpr = _exprList.Next();
    }
}

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

void CegoFunction::setCounterId(const Chain& counterId)
{
    _counterId = counterId;
}

void CegoFunction::setCounterExpr(CegoExpr *pExpr)
{
    _exprList.Insert(pExpr);
}

ListT<CegoAttrDesc*> CegoFunction::getAttrRefList() const
{
    ListT<CegoAttrDesc*> attrList;
    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	attrList += (*pExpr)->getAttrRefList();
	pExpr = _exprList.Next();
    }
    return attrList;
}

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

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

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

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

    }
    return aggList;
}

CegoFieldValue CegoFunction::evalFieldValue(ListT<CegoField>** pFLA, CegoProcBlock *pBlock)
{
    switch ( _type ) 
    {
    case CegoFunction::INT2ASC:
    {
	CegoExpr** pExpr1 = _exprList.First();
	
	CegoFieldValue fv1;
	
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);

	if ( fv1.getType() == NULL_TYPE )
	    return CegoFieldValue();

	if ( fv1.castTo(INT_TYPE) == false )
	{
	    Chain msg = Chain("Invalid type for ascii conversion"); 
	    throw Exception(EXLOC, msg);	    
	}

	int val = 0; 
	if ( fv1.getValue() != 0 )
	    memcpy(&val, fv1.getValue(), sizeof(int));

	if ( val > 127 || val < 0 )
	{
	    Chain msg = Chain("Integer value out of range for ascii conversion"); 
	    throw Exception(EXLOC, msg);	    	    
	}
	char c = (char)val;
	
	CegoFieldValue fv = CegoFieldValue(VARCHAR_TYPE, Chain(c));	
		
	return fv;
    }
    case CegoFunction::ASC2INT:
    {
	CegoExpr** pExpr1 = _exprList.First();
	
	CegoFieldValue fv1;
	
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);
	
	if ( fv1.getType() == NULL_TYPE )
	    return CegoFieldValue();

	if ( fv1.castTo(VARCHAR_TYPE) == false )
	{
	    Chain msg = Chain("Invalid type for ascii conversion"); 
	    throw Exception(EXLOC, msg);	    
	}

	if ( fv1.getLength() != 2 )
	{
	    Chain msg = Chain("Invalid length for ascii conversion"); 
	    throw Exception(EXLOC, msg);	    
	}

	char c;
	memcpy(&c, fv1.getValue(), sizeof(char));
	int i = c;

	CegoFieldValue fv = CegoFieldValue(INT_TYPE, &i, sizeof(int), false);	
		
	return fv;      	
    }
    case CegoFunction::ROUND:
    {	
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	int precision = 0;

	if ( pExpr2 != 0 )
	{
	    CegoFieldValue pv = (*pExpr2)->evalFieldValue(pFLA, pBlock);
	    
	    if ( pv.getType() != INT_TYPE )
	    {
		Chain msg = Chain("Invalid precision in function round"); 
		throw Exception(EXLOC, msg);
	    }
	    if ( pv.getValue() != 0 )
		memcpy(&precision, pv.getValue(), sizeof(int));
	    // precision = *((int*)pv.getValue());
	}
	
	CegoFieldValue fv;
	
	fv = (*pExpr1)->evalFieldValue(pFLA, pBlock);
	
	Tokenizer tok(fv.valAsChain(), Chain("."));

	Chain lpart;
	tok.nextToken(lpart);
	Chain rpart;
	tok.nextToken(rpart);
	
	CegoFieldValue retVal;
	if ( precision > 0 )
	{	    
	    retVal = CegoFieldValue(VARCHAR_TYPE, lpart + Chain(".") + rpart.subChain(1, precision));
	}
	else
	{
	    retVal = CegoFieldValue(INT_TYPE, lpart);
	}
	return retVal;
    }
    case CegoFunction::SCANDATE:
    {	
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);
	fv2 = (*pExpr2)->evalFieldValue(pFLA, pBlock);

	Datetime dt(fv2.valAsChain(), fv1.valAsChain());

	unsigned long long *pDV = new (unsigned long long);
	*pDV = dt.asLong();	
	CegoFieldValue fv(DATETIME_TYPE, pDV, sizeof(unsigned long long), true);
	
	return fv;	
    }
    case CegoFunction::DATE2STR:
    {		
	CegoFieldValue fv;
	
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);
	fv2 = (*pExpr2)->evalFieldValue(pFLA, pBlock);

	if ( fv1.getType() == NULL_TYPE )
	    return fv;

	if ( fv1.castTo(DATETIME_TYPE) == false )
	{
	    Chain msg = Chain("Cannot cast to datetime"); 
	    throw Exception(EXLOC, msg);	    
	}

	long long val = 0; 
	if ( fv1.getValue() != 0 )
	    memcpy(&val, fv1.getValue(), sizeof(long long));

	Datetime dt;

	if ( val != 0 )
	{
	    dt = Datetime(val);
	}

	fv = CegoFieldValue(VARCHAR_TYPE, dt.asChain(fv2.valAsChain()));
	
	return fv;	
    }
    case CegoFunction::DATE2LONG:
    {
	CegoExpr** pExpr1 = _exprList.First();
	
	CegoFieldValue fv1;
	
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);

	if ( fv1.getType() == NULL_TYPE )
	    return CegoFieldValue();

	if ( fv1.castTo(DATETIME_TYPE) == false )
	{
	    Chain msg = Chain("Cannot cast to datetime"); 
	    throw Exception(EXLOC, msg);	    
	}

	long long dateVal = 0; 
	if ( fv1.getValue() != 0 )
	    memcpy(&dateVal, fv1.getValue(), sizeof(long long));
	if ( dateVal == 0 )
	{	   
	    Datetime dt;
	    dateVal = dt.asLong();
	}
	CegoFieldValue fv = CegoFieldValue(LONG_TYPE, Chain(dateVal));
	return fv;	
    }
    case CegoFunction::LONG2DATE:
    {			
	CegoExpr** pExpr1 = _exprList.First();
	
	CegoFieldValue fv1;	
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);

	if ( fv1.getType() == NULL_TYPE )
	    return CegoFieldValue();

	if ( fv1.castTo(LONG_TYPE) == false )
	{
	    Chain msg = Chain("Cannot cast to long"); 
	    throw Exception(EXLOC, msg);	    	    
	}
	long long *pVal = new long long;
	if ( fv1.getValue() != 0 )
	    memcpy(pVal, fv1.getValue(), sizeof(long long));
	else
	    *pVal = 0;

	CegoFieldValue fv = CegoFieldValue(DATETIME_TYPE, pVal, sizeof(long long), true);
	return fv;
    }
    case CegoFunction::NEWDATE:
    {
	// we stay on signed variables, since these values are internally handeled as int
        int year = 0;
	int month = 1;
	int day = 1;
	int hour = 0;
	int minute = 0;
	int second = 0;
	
	CegoExpr** pYearExpr = _exprList.First();
	if ( pYearExpr )
	{
	    CegoFieldValue yearVal;	
	    yearVal = (*pYearExpr)->evalFieldValue(pFLA, pBlock);
	    
	    if ( yearVal.castTo(INT_TYPE) == false )
	    {
		Chain msg = Chain("Cannot cast year to int"); 
		throw Exception(EXLOC, msg);	    	    
	    }
	    	
	    memcpy(&year, yearVal.getValue(), sizeof(int));
		    
	    CegoExpr** pMonthExpr = _exprList.Next();

	    if ( pMonthExpr )
	    {		
		CegoFieldValue monthVal;	
		monthVal = (*pMonthExpr)->evalFieldValue(pFLA, pBlock);
		
		if ( monthVal.castTo(INT_TYPE) == false )
		{
		    Chain msg = Chain("Cannot cast month to int"); 
		    throw Exception(EXLOC, msg);	    	    
		}
		
		memcpy(&month, monthVal.getValue(), sizeof(int));
		
		CegoExpr** pDayExpr = _exprList.Next();

		if ( pDayExpr )
		{
		    CegoFieldValue dayVal;	
		    dayVal = (*pDayExpr)->evalFieldValue(pFLA, pBlock);
		    
		    if ( dayVal.castTo(INT_TYPE) == false )
		    {
			Chain msg = Chain("Cannot cast day to int"); 
			throw Exception(EXLOC, msg);	    	    
		    }
		    
		    memcpy(&day, dayVal.getValue(), sizeof(int));
		    		    
		    CegoExpr** pHourExpr = _exprList.Next();

		    if ( pHourExpr )
		    {
			CegoFieldValue hourVal;	
			hourVal = (*pHourExpr)->evalFieldValue(pFLA, pBlock);
			
			if ( hourVal.castTo(INT_TYPE) == false )
			{
			    Chain msg = Chain("Cannot cast hour to int"); 
			    throw Exception(EXLOC, msg);	    	    
			}		
			
			memcpy(&hour, hourVal.getValue(), sizeof(int));
			
			CegoExpr** pMinuteExpr = _exprList.Next();

			if ( pMinuteExpr )
			{
			    CegoFieldValue minuteVal;	
			    minuteVal = (*pMinuteExpr)->evalFieldValue(pFLA, pBlock);
			    
			    if ( minuteVal.castTo(INT_TYPE) == false )
			    {
				Chain msg = Chain("Cannot cast minute to int"); 
				throw Exception(EXLOC, msg);	    	    
			    }
			    
			    memcpy(&minute, minuteVal.getValue(), sizeof(int));
			    
			    CegoExpr** pSecondExpr = _exprList.Next();

			    if ( pSecondExpr )
			    {
				CegoFieldValue secondVal;	
				secondVal = (*pSecondExpr)->evalFieldValue(pFLA, pBlock);
				
				if ( secondVal.castTo(INT_TYPE) == false )
				{
				    Chain msg = Chain("Cannot cast second to int"); 
				    throw Exception(EXLOC, msg);	    	    
				}				
				memcpy(&second, secondVal.getValue(), sizeof(int));	
			    }
			}
		    }
		}
	    }
	}
	
	long long *pDateTimeValue = new long long;
	
	Datetime dt(year, month, day, hour, minute, second);
	*pDateTimeValue = dt.asLong();
	
	CegoFieldValue fv = CegoFieldValue(DATETIME_TYPE, pDateTimeValue, sizeof(long long), true);
	return fv;
    }    
    case CegoFunction::TRUNC:
    {
	CegoExpr** pExpr = _exprList.First();
	
	CegoFieldValue fv1;

	fv1 = (*pExpr)->evalFieldValue(pFLA, pBlock);

	if ( fv1.getType() == NULL_TYPE )	
	    return CegoFieldValue();	
	
	Tokenizer t(fv1.valAsChain(), ".");
	Chain truncVal;
	t.nextToken(truncVal);
	
	CegoFieldValue fv(INT_TYPE, truncVal);
	return fv;
    }
    case CegoFunction::LOWER:
    {
	CegoExpr** pExpr = _exprList.First();
	
	CegoFieldValue fv1;
	
	fv1 = (*pExpr)->evalFieldValue(pFLA, pBlock);

	if ( fv1.getType() == NULL_TYPE )	
	    return CegoFieldValue();	
	
	CegoFieldValue fv(VARCHAR_TYPE, fv1.valAsChain().toLower());
	return fv;
    }
    case CegoFunction::UPPER:
    {	
	CegoExpr** pExpr = _exprList.First();
	
	CegoFieldValue fv1;
	
	fv1 = (*pExpr)->evalFieldValue(pFLA, pBlock);

	if ( fv1.getType() == NULL_TYPE )	
	    return CegoFieldValue();	

	CegoFieldValue fv(VARCHAR_TYPE, fv1.valAsChain().toUpper());
	return fv;
    }
    case CegoFunction::RIGHT:
    {	
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);
	fv2 = (*pExpr2)->evalFieldValue(pFLA, pBlock);

	if ( fv2.getType() != INT_TYPE )
	{
	    Chain msg = Chain("Invalid datatype in function right"); 
	    throw Exception(EXLOC, msg);
	}
	int len = 0; 
	if ( fv2.getValue() != 0 )
	    memcpy(&len, fv2.getValue(), sizeof(int));
	// len = *((int*)fv2.getValue());
			
	Chain right;
	if ( len < (int)fv1.valAsChain().length() )
	    right = fv1.valAsChain().subChain(fv1.valAsChain().length() - len, fv1.valAsChain().length());
	else
	    right = fv1.valAsChain();
	
	CegoFieldValue fv(VARCHAR_TYPE, right);
	return fv;
    }
    case CegoFunction::LEFT:
    {
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);
	fv2 = (*pExpr2)->evalFieldValue(pFLA, pBlock);

	if ( fv2.getType() != INT_TYPE )
	{
	    Chain msg = Chain("Invalid datatype in function right"); 
	    throw Exception(EXLOC, msg);
	}

	int len = 0; 
	if ( fv2.getValue() != 0 )
	    memcpy(&len, fv2.getValue(), sizeof(int));
	// len = *((int*)fv2.getValue());
	
	Chain left;
	if ( len < (int)fv1.valAsChain().length() )
	    left = fv1.valAsChain().subChain(1, len);
	else
	    left = fv1.valAsChain();
	
	CegoFieldValue fv(VARCHAR_TYPE, left);
	return fv;
    }
    case CegoFunction::GETPOS:
    {    
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	CegoExpr** pExpr3 = _exprList.Next();
	CegoExpr** pExpr4 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;

	// start may be -1 to indicate search from end
	int start = 0;
	unsigned occ = 1;
	
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);
	fv2 = (*pExpr2)->evalFieldValue(pFLA, pBlock);

	if ( pExpr3 )
	{
	    CegoFieldValue fv = (*pExpr3)->evalFieldValue(pFLA, pBlock);
	    start = fv.valAsChain().asInteger();    
	}
	if ( pExpr4 )
	{
	    CegoFieldValue fv = (*pExpr4)->evalFieldValue(pFLA, pBlock);
	    occ = fv.valAsChain().asUnsigned();    
	}

	Chain s = fv1.valAsChain();
			
	unsigned long pos;
	if ( s.posStr(fv2.valAsChain(), pos, start, occ) )
	{		
	    CegoFieldValue fv(INT_TYPE, pos);
	    return fv;
	}
	
	CegoFieldValue nullField;	
	return nullField;
    }
    case CegoFunction::SUBSTR:
    {
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	CegoExpr** pExpr3 = _exprList.Next();
	
	CegoFieldValue fv1, fv2, fv3;
	
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);
	fv2 = (*pExpr2)->evalFieldValue(pFLA, pBlock);
	
	Chain s = fv1.valAsChain();
	unsigned start = fv2.valAsChain().asUnsigned();
		
	unsigned len=0;
	
	if ( pExpr3 )
	{
	    fv3 = (*pExpr3)->evalFieldValue(pFLA, pBlock);
	    len=fv3.valAsChain().asUnsigned();
	}

	// we start at min at position 1
	if ( start < 1 )
	    start = 1;

	// we start at max s.length()
	if ( start > (unsigned)s.length() )
	{
	    start = (unsigned)s.length();
	    // throw Exception(EXLOC, "Start postion after end");
	}
		
	if ( start+len-1 > (unsigned)s.length())
	{
	    len = s.length() - start;
	    // throw Exception(EXLOC, "End postion after end");
	}
	
	Chain sub;
	if ( len > 0 )
	{
	    sub = s.subChain(start, start+len-1);
	}
	else
	{
	    sub = s.subChain(start, s.length());
	}
	
	CegoFieldValue fv(VARCHAR_TYPE, sub);
	
	return fv;
    }
    case CegoFunction::REPLACE:
    {    
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	CegoExpr** pExpr3 = _exprList.Next();
	
	CegoFieldValue fv1, fv2, fv3;
	
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);
	fv2 = (*pExpr2)->evalFieldValue(pFLA, pBlock);
	fv3 = (*pExpr3)->evalFieldValue(pFLA, pBlock);

	if  ( fv2.isNull() )
        {
            Chain msg = Chain("Search pattern cannot be empty");
            throw Exception(EXLOC, msg);
        }

        Chain src = fv1.valAsChain();
        Chain search = fv2.valAsChain();

        Chain replace;
        if ( ! fv3.isNull() )
            replace = fv3.valAsChain();
		
	Chain res;
	src.replaceAll(search, replace, res);
	
	CegoFieldValue fv(VARCHAR_TYPE, res);
	return fv;
    }
    case CegoFunction::REGMATCH:
    {    
	if ( _pTabMng == 0 )
	    throw Exception(EXLOC, "No valid table manager set up");

	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	CegoExpr** pExpr3 = _exprList.Next();

	CegoExpr** pExpr4 = _exprList.Next();

	Chain matchVar;
	
	if ( pExpr4 )
	{
	    if ( (*pExpr4)->checkVar(matchVar) == false )
	    {
		Chain msg = Chain("Invalid argument for replace count variable");
		throw Exception(EXLOC, msg);		
	    }
	}
	CegoFieldValue fv1, fv2, fv3;
	
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);

	if  ( fv1.isNull() )
        {
            Chain msg = Chain("Search attern cannot be empty");
            throw Exception(EXLOC, msg);
        }

	fv2 = (*pExpr2)->evalFieldValue(pFLA, pBlock);

	if  ( fv2.isNull() )
        {
            Chain msg = Chain("Replace pattern cannot be empty");
            throw Exception(EXLOC, msg);
        }

	fv3 = (*pExpr3)->evalFieldValue(pFLA, pBlock);
       
	if  ( fv3.isNull() )
        {
            Chain msg = Chain("Source string cannot be empty");
            throw Exception(EXLOC, msg);
        }

	Chain pattern = fv1.valAsChain();
	Chain replace = fv2.valAsChain();
	Chain src = fv3.valAsChain();

	CegoReplacer *pRep = _pTabMng->getReplacer(pattern, replace);
	   
	Chain target;
	unsigned nmatch = pRep->replace(src, target);

	if ( pExpr4 )
	{
	    CegoFieldValue matchVal(INT_TYPE, Chain(nmatch));
	    pBlock->setValue(matchVar, matchVal); 
	}
	
	CegoFieldValue retVal(VARCHAR_TYPE, target);
	return retVal;
    }

    case CegoFunction::LENGTH:
    {
	CegoExpr** pExpr1 = _exprList.First();
	
	CegoFieldValue fv1;
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);

	if ( fv1.getType() == NULL_TYPE )	
	    return CegoFieldValue();	

	Chain s = fv1.valAsChain();
	
	CegoFieldValue fv(INT_TYPE, s.length() - 1);

	return fv;
    }
    case CegoFunction::TRIM:
    {	
	CegoExpr** pExpr1 = _exprList.First();

	CegoFieldValue fv1;
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);
	
	CegoExpr** pExpr2 = _exprList.Next();

	CegoFieldValue fv2;
	fv2 = (*pExpr2)->evalFieldValue(pFLA, pBlock);
	
	Chain s = fv1.valAsChain();
		
	Chain t = s.cutTrailing(fv2.valAsChain());
				    
	CegoFieldValue fv(VARCHAR_TYPE, t);
	return fv;
    }
    case CegoFunction::RTRIM:
    {	
	CegoExpr** pExpr1 = _exprList.First();

	CegoFieldValue fv1;
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);
	
	CegoExpr** pExpr2 = _exprList.Next();

	CegoFieldValue fv2;
	fv2 = (*pExpr2)->evalFieldValue(pFLA, pBlock);
	
	Chain s = fv1.valAsChain();
		
	Chain t = s.truncRight(fv2.valAsChain());
				    
	CegoFieldValue fv(VARCHAR_TYPE, t);
	return fv;
    }
    case CegoFunction::LTRIM:
    {	
	CegoExpr** pExpr1 = _exprList.First();

	CegoFieldValue fv1;
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);
	
	CegoExpr** pExpr2 = _exprList.Next();

	CegoFieldValue fv2;
	fv2 = (*pExpr2)->evalFieldValue(pFLA, pBlock);
	
	Chain s = fv1.valAsChain();
		
	Chain t = s.truncLeft(fv2.valAsChain());
				    
	CegoFieldValue fv(VARCHAR_TYPE, t);
	return fv;
    }
    case CegoFunction::STR2INT:
    {	
	CegoExpr** pExpr = _exprList.First();
	
	CegoFieldValue fv1;

	fv1 = (*pExpr)->evalFieldValue(pFLA, pBlock);

	if ( fv1.getType() == NULL_TYPE )	
	    return CegoFieldValue();	
	
	CegoFieldValue fv(INT_TYPE, fv1.valAsChain());
	return fv;
    }
    case CegoFunction::STR2LONG:
    {	
	CegoExpr** pExpr = _exprList.First();
	
	CegoFieldValue fv;

	fv = (*pExpr)->evalFieldValue(pFLA, pBlock);
	
	CegoFieldValue retVal(LONG_TYPE, fv.valAsChain());
	return retVal;
    }
    case CegoFunction::RANDSTR:
    {	
	CegoExpr** pExpr = _exprList.First();
	
	CegoFieldValue fv;

	fv = (*pExpr)->evalFieldValue(pFLA, pBlock);

	unsigned l = (unsigned)random() % fv.valAsChain().asUnsigned();
	if ( l == 0 )
	    l = fv.valAsChain().asUnsigned();
	
	Chain rs;
	for ( unsigned j=0; j<l; j++ ) 
	{ 
	    rs += Chain((char)(65 + (random() % 26))); 
	}
	
	CegoFieldValue retVal(VARCHAR_TYPE, rs);
	return retVal;
    }
    case CegoFunction::RANDINT:
    {	
	CegoExpr** pExpr = _exprList.First();
	
	CegoFieldValue fv;

	fv = (*pExpr)->evalFieldValue(pFLA, pBlock);
	
	unsigned l = fv.valAsChain().asUnsigned();

	CegoFieldValue retVal(INT_TYPE, random() % l);  
	return retVal;
    }
    case CegoFunction::MOD:
    {	
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);
	fv2 = (*pExpr2)->evalFieldValue(pFLA, pBlock);

	if ( fv1.castTo(INT_TYPE) == false )	    
	{
	    Chain msg = Chain("Invalid datatype in function mod"); 
	    throw Exception(EXLOC, msg);
	}

	if ( fv2.castTo(INT_TYPE) == false )	    
	{
	    Chain msg = Chain("Invalid datatype in function mod"); 
	    throw Exception(EXLOC, msg);
	}

	int op1 = 0;
	if ( fv1.getValue() != 0 )
	    memcpy(&op1, fv1.getValue(), sizeof(int));
	// cast to long

	int op2 = 0;
	if ( fv2.getValue() != 0 )
	    memcpy(&op2, fv2.getValue(), sizeof(int));

	if ( op2 == 0 )
	    throw Exception(EXLOC, "Division by zero");
	
	int modval = op1 % op2;
	CegoFieldValue fv(INT_TYPE, modval);
	return fv;	
    }
    case CegoFunction::LMOD:
    {
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);
	fv2 = (*pExpr2)->evalFieldValue(pFLA, pBlock);

	if ( fv1.castTo(LONG_TYPE) == false )	    
	{
	    Chain msg = Chain("Invalid datatype in function lmod"); 
	    throw Exception(EXLOC, msg);
	}

	if ( fv2.castTo(LONG_TYPE) == false )	    
	{
	    Chain msg = Chain("Invalid datatype in function lmod"); 
	    throw Exception(EXLOC, msg);
	}
	
	long long op1 = 0;
	if ( fv1.getValue() != 0 )
	    memcpy(&op1, fv1.getValue(), sizeof(long long));

	long long op2 = 0;
	if ( fv2.getValue() != 0 )
	    memcpy(&op2, fv2.getValue(), sizeof(long long));

	if ( op2 == 0 )
	    throw Exception(EXLOC, "Division by zero");
	
	long long modval = op1 % op2;
	CegoFieldValue fv(LONG_TYPE, modval);
	return fv;	
    }
    case CegoFunction::DIV:
    {
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);
	fv2 = (*pExpr2)->evalFieldValue(pFLA, pBlock);

	if ( fv1.castTo(INT_TYPE) == false )	    
	{
	    Chain msg = Chain("Invalid datatype in function div"); 
	    throw Exception(EXLOC, msg);
	}

	if ( fv2.castTo(INT_TYPE) == false )	    
	{
	    Chain msg = Chain("Invalid datatype in function div"); 
	    throw Exception(EXLOC, msg);
	}

	int op1 = 0;
	if ( fv1.getValue() != 0 )
	    memcpy(&op1, fv1.getValue(), sizeof(int));

	int op2 = 0;
	if ( fv2.getValue() != 0 )
	    memcpy(&op2, fv2.getValue(), sizeof(int));

	if ( op2 == 0 )
	    throw Exception(EXLOC, "Division by zero");
	
	int divval = op1 / op2;
	CegoFieldValue fv(INT_TYPE, divval);
	return fv;		
    }
    case CegoFunction::LDIV:
    {
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);
	fv2 = (*pExpr2)->evalFieldValue(pFLA, pBlock);

	if ( fv1.castTo(LONG_TYPE) == false )	    
	{
	    Chain msg = Chain("Invalid datatype in function ldiv"); 
	    throw Exception(EXLOC, msg);
	}

	if ( fv2.castTo(LONG_TYPE) == false )	    
	{
	    Chain msg = Chain("Invalid datatype in function ldiv"); 
	    throw Exception(EXLOC, msg);
	}
	
	long long op1 = 0;
	if ( fv1.getValue() != 0 )
	    memcpy(&op1, fv1.getValue(), sizeof(long long));

	long long op2 = 0;
	if ( fv2.getValue() != 0 )
	    memcpy(&op2, fv2.getValue(), sizeof(long long));

	if ( op2 == 0 )
	    throw Exception(EXLOC, "Division by zero");
	
	long long divval = op1 / op2;
	CegoFieldValue fv(LONG_TYPE, divval);
	return fv;	
    }
    case CegoFunction::POWER:
    {
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);
	fv2 = (*pExpr2)->evalFieldValue(pFLA, pBlock);

	if ( fv1.getType() != INT_TYPE || fv2.getType() != INT_TYPE )
	{
	    Chain msg = Chain("Invalid datatype in function power"); 
	    throw Exception(EXLOC, msg);
	}
	
	int op1 = 0;
	if ( fv1.getValue() != 0 )
	    memcpy(&op1, fv1.getValue(), sizeof(int));
	
	int op2 = 0;
	if ( fv2.getValue() != 0 )
	    memcpy(&op2, fv2.getValue(), sizeof(int));
	
	int i,p;
	p = 1;
	for (i = 1; i <= op2; ++i)
	    p *= op1;
	
	CegoFieldValue fv(INT_TYPE, p);
	return fv;	
    }
    case CegoFunction::BITAND:
    {
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);
	fv2 = (*pExpr2)->evalFieldValue(pFLA, pBlock);

	if ( fv1.getType() != INT_TYPE || fv2.getType() != INT_TYPE )
	{
	    Chain msg = Chain("Invalid datatype in function bitand"); 
	    throw Exception(EXLOC, msg);
	}
	
	int op1 = 0;
	if ( fv1.getValue() != 0 )
	    memcpy(&op1, fv1.getValue(), sizeof(int));
	
	int op2 = 0;
	if ( fv2.getValue() != 0 )
	    memcpy(&op2, fv2.getValue(), sizeof(int));
	
	int a = op1 & op2;

	CegoFieldValue fv(INT_TYPE, a);
	return fv;	
    }
    case CegoFunction::BITOR:
    {
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);
	fv2 = (*pExpr2)->evalFieldValue(pFLA, pBlock);

	if ( fv1.getType() != INT_TYPE || fv2.getType() != INT_TYPE )
	{
	    Chain msg = Chain("Invalid datatype in function bitor"); 
	    throw Exception(EXLOC, msg);
	}
	
	int op1 = 0;
	if ( fv1.getValue() != 0 )
	    memcpy(&op1, fv1.getValue(), sizeof(int));
	
	int op2 = 0;
	if ( fv2.getValue() != 0 )
	    memcpy(&op2, fv2.getValue(), sizeof(int));
	
	int o = op1 | op2;

	CegoFieldValue fv(INT_TYPE, o);
	return fv;
    }
    case CegoFunction::BITXOR:
    {
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	fv1 = (*pExpr1)->evalFieldValue(pFLA, pBlock);
	fv2 = (*pExpr2)->evalFieldValue(pFLA, pBlock);

	if ( fv1.getType() != INT_TYPE || fv2.getType() != INT_TYPE )
	{
	    Chain msg = Chain("Invalid datatype in function bitxcor"); 
	    throw Exception(EXLOC, msg);
	}
	
	int op1 = 0;
	if ( fv1.getValue() != 0 )
	    memcpy(&op1, fv1.getValue(), sizeof(int));
	
	int op2 = 0;
	if ( fv2.getValue() != 0 )
	    memcpy(&op2, fv2.getValue(), sizeof(int));
	
	int xo = op1 ^ op2;

	CegoFieldValue fv(INT_TYPE, xo);
	return fv;	
    }
    case CegoFunction::BLOBSIZE:
    {
	if ( _pTabMng == 0 )
	    throw Exception(EXLOC, "No valid table manager set up");
			
	CegoExpr** pExpr = _exprList.First();

	unsigned long long blobSize = 0;	
	CegoFieldValue fv;
	
	fv = (*pExpr)->evalFieldValue(pFLA, pBlock);

	if ( fv.getType() == NULL_TYPE )
	{
	    CegoFieldValue rfv(LONG_TYPE, blobSize);
	    return rfv;	    
	}
	
	if ( fv.getType() != BLOB_TYPE )
	{
	    Chain msg = Chain("Invalid datatype in function blobsize"); 
	    throw Exception(EXLOC, msg);
	}
	
	Tokenizer tok(fv.valAsChain(), Chain(LOBSEP));

	Chain pstr;
	PageIdType pageId = 0;
	if ( tok.nextToken(pstr) )
	{
	    pageId = pstr.asUnsignedLongLong();
	}
	else
	{
	    Chain msg = Chain("Cannot get pageid from blob value"); 
	    throw Exception(EXLOC, msg);	   
	}	

	CegoDatabaseManager* pDBMng = _pTabMng->getDBMng();
	CegoLockHandler* pLockHandle = _pTabMng->getLockHandler();

	CegoBufferPage bp;
	try
	{
	    pDBMng->bufferFix(bp, _tabSetId, pageId, CegoBufferPool::SYNC, pLockHandle);	    
	    memcpy (&blobSize, bp.getChunkEntry() + sizeof(unsigned long long), sizeof(unsigned long long));
	    pDBMng->bufferUnfix(bp, true, pLockHandle);
	}
	catch ( Exception e )
	{
	    if ( bp.isFixed() )
		pDBMng->bufferUnfix(bp, true, pLockHandle);
	}

	CegoFieldValue rfv(LONG_TYPE, blobSize);
	return rfv;	
    }
    case CegoFunction::BLOBREF:
    {
	if ( _pTabMng == 0 )
	    throw Exception(EXLOC, "No valid table manager set up");

	CegoExpr** pExpr = _exprList.First();

	unsigned long long blobRef = 0;	
	CegoFieldValue fv;
	
	fv = (*pExpr)->evalFieldValue(pFLA, pBlock);

	if ( fv.getType() == NULL_TYPE )
	{
	    CegoFieldValue rfv(LONG_TYPE, blobRef);
	    return rfv;	    
	}
	
	if ( fv.getType() != BLOB_TYPE )
	{
	    Chain msg = Chain("Invalid datatype in function blobref"); 
	    throw Exception(EXLOC, msg);
	}
	
	Tokenizer tok(fv.valAsChain(), Chain(LOBSEP));

	Chain pstr;
	PageIdType pageId = 0;
	if ( tok.nextToken(pstr) )
	{
	    pageId = pstr.asUnsignedLongLong();
	}
	else
	{
	    Chain msg = Chain("Cannot get pageid from blob value"); 
	    throw Exception(EXLOC, msg);	   
	}	

	CegoDatabaseManager* pDBMng = _pTabMng->getDBMng();
	CegoLockHandler* pLockHandle = _pTabMng->getLockHandler();

	CegoBufferPage bp;
	try
	{
	    pDBMng->bufferFix(bp, _tabSetId, pageId, CegoBufferPool::SYNC, pLockHandle);	    
	    memcpy (&blobRef, bp.getChunkEntry(), sizeof(unsigned long long));
	    pDBMng->bufferUnfix(bp, true, pLockHandle);
	}
	catch ( Exception e )
	{
	    if ( bp.isFixed() )
		pDBMng->bufferUnfix(bp, true, pLockHandle);
	}

	CegoFieldValue rfv(LONG_TYPE, blobRef);
	return rfv;	
    }
    case CegoFunction::CLOBSIZE:
    {
	if ( _pTabMng == 0 )
	    throw Exception(EXLOC, "No valid table manager set up");

	CegoExpr** pExpr = _exprList.First();

	unsigned long long clobSize = 0;
	CegoFieldValue fv;
	
	fv = (*pExpr)->evalFieldValue(pFLA, pBlock);

	if ( fv.getType() == NULL_TYPE )
	{
	    CegoFieldValue rfv(LONG_TYPE, clobSize);
	    return rfv;	    
	}
	
	if ( fv.getType() != CLOB_TYPE )
	{
	    Chain msg = Chain("Invalid datatype in function clobsize"); 
	    throw Exception(EXLOC, msg);
	}
	
	Tokenizer tok(fv.valAsChain(), Chain(LOBSEP));
	Chain pstr;
	PageIdType pageId = 0;
	if ( tok.nextToken(pstr) )
	{
	    pageId = pstr.asUnsignedLongLong();
	}
	else
	{
	    Chain msg = Chain("Cannot get pageid from clob value"); 
	    throw Exception(EXLOC, msg);	   
	}	

	CegoDatabaseManager* pDBMng = _pTabMng->getDBMng();
	CegoLockHandler* pLockHandle = _pTabMng->getLockHandler();

	CegoBufferPage bp;
	try
	{
	    pDBMng->bufferFix(bp, _tabSetId, pageId, CegoBufferPool::SYNC, pLockHandle);	    
	    memcpy (&clobSize, bp.getChunkEntry() + sizeof(unsigned long long), sizeof(unsigned long long));
	    pDBMng->bufferUnfix(bp, true, pLockHandle);
	}
	catch ( Exception e )
	{
	    if ( bp.isFixed() )
		pDBMng->bufferUnfix(bp, true, pLockHandle);
	}

	CegoFieldValue rfv(LONG_TYPE, clobSize);
	return rfv;	
    }
    case CegoFunction::CLOBREF:
    {
	if ( _pTabMng == 0 )
	    throw Exception(EXLOC, "No valid table manager set up");

	CegoExpr** pExpr = _exprList.First();

	unsigned long long clobRef = 0;
	CegoFieldValue fv;
	
	fv = (*pExpr)->evalFieldValue(pFLA, pBlock);

	if ( fv.getType() == NULL_TYPE )
	{
	    CegoFieldValue rfv(LONG_TYPE, clobRef);
	    return rfv;	    
	}
	
	if ( fv.getType() != CLOB_TYPE )
	{
	    Chain msg = Chain("Invalid datatype in function clobref"); 
	    throw Exception(EXLOC, msg);
	}
	
	Tokenizer tok(fv.valAsChain(), Chain(LOBSEP));
	Chain pstr;
	PageIdType pageId = 0;
	if ( tok.nextToken(pstr) )
	{
	    pageId = pstr.asUnsignedLongLong();
	}
	else
	{
	    Chain msg = Chain("Cannot get pageid from clob value"); 
	    throw Exception(EXLOC, msg);	   
	}	

	CegoDatabaseManager* pDBMng = _pTabMng->getDBMng();
	CegoLockHandler* pLockHandle = _pTabMng->getLockHandler();

	CegoBufferPage bp;
	try
	{
	    pDBMng->bufferFix(bp, _tabSetId, pageId, CegoBufferPool::SYNC, pLockHandle);	    
	    memcpy (&clobRef, bp.getChunkEntry(), sizeof(unsigned long long));
	    pDBMng->bufferUnfix(bp, true, pLockHandle);
	}
	catch ( Exception e )
	{
	    if ( bp.isFixed() )
		pDBMng->bufferUnfix(bp, true, pLockHandle);
	}

	CegoFieldValue rfv(LONG_TYPE, clobRef);
	return rfv;	
    }
    case CegoFunction::CLOB2STR:
    {
	if ( _pTabMng == 0 )
	    throw Exception(EXLOC, "No valid table manager set up");

	CegoExpr** pExpr1 = _exprList.First();
	
	CegoFieldValue fv;
	
	fv = (*pExpr1)->evalFieldValue(pFLA, pBlock);

	if ( fv.getType() == NULL_TYPE )
	{
	    CegoFieldValue zs(VARCHAR_TYPE, Chain());
	    return zs;	    
	}

	if ( fv.getType() != CLOB_TYPE )
	{
	    Chain msg = Chain("Invalid datatype in function clob2str"); 
	    throw Exception(EXLOC, msg);
	}
		
	Tokenizer tok(fv.valAsChain(), Chain(LOBSEP));
	Chain pstr;
	PageIdType pageId = 0;

	if ( tok.nextToken(pstr) )
	{
	    pageId = pstr.asUnsignedLong();
	}
	else
	{
	    Chain msg = Chain("Cannot get pageid from clob value"); 
	    throw Exception(EXLOC, msg);	   
	}

	unsigned long long clobSize;

	char* pC = _pTabMng->getClobData(_tabSetId, pageId, clobSize);
	
	// memory is allocated by getClobData, so we build CegoFieldValue with localCopy = true
	bool isLocalCopy = true;

	// we construct field value with zero termination character
	CegoFieldValue rfv(VARCHAR_TYPE, pC, clobSize + 1, isLocalCopy);
	
	return rfv;
    }   
    case CegoFunction::NEXTCOUNT:
    {
	if ( _pTabMng == 0 )
	    throw Exception(EXLOC, "No valid table manager set up");

	long v = _pTabMng->getDBMng()->getCounterValue(_tabSetId, _counterId, 1);
	CegoFieldValue retVal(LONG_TYPE, Chain(v));
	return retVal;
    }
    case CegoFunction::SETCOUNT:
    {
	if ( _pTabMng == 0 )
	    throw Exception(EXLOC, "No valid table manager set up");
		
	CegoFieldValue fv;
	CegoExpr** pCounterExpr = _exprList.First();		
	fv = (*pCounterExpr)->evalFieldValue(pFLA, pBlock);	
	fv.castTo(LONG_TYPE);

	if ( fv.getType() != LONG_TYPE )
	{
	    Chain msg = Chain("Invalid datatype in function setcount"); 
	    throw Exception(EXLOC, msg);
	}

	long l = fv.valAsChain().asLong();

	long v = _pTabMng->getDBMng()->setCounterValue(_tabSetId, _counterId, l);

	CegoFieldValue retVal(LONG_TYPE, Chain(v));
	return retVal;
    }
    case CegoFunction::GETCOUNT:
    {
	if ( _pTabMng == 0 )
	    throw Exception(EXLOC, "No valid table manager set up");
		
	long v = _pTabMng->getDBMng()->getCounterValue(_tabSetId, _counterId);
	CegoFieldValue retVal(LONG_TYPE, Chain(v));
	return retVal;
    }
    default:
    // case CegoFunction::USERDEFINED:
    {
	if ( _pTabMng == 0 )
	    throw Exception(EXLOC, "No valid table manager set up");
	
	CegoFieldValue retVal;      

	if ( _pProc == 0 )
	{
	    _pTabMng->getDBMng()->useObject(_tabSetId, _funcName, CegoObject::PROCEDURE, CegoDatabaseManager::SHARED, _pTabMng);

	    try 
	    {	    
		_pProc = _pTabMng->getProcedure(_tabSetId, _funcName);
	    }
	    catch ( Exception e )
	    {
		_pTabMng->getDBMng()->unuseObject(_tabSetId, _funcName, CegoObject::PROCEDURE);
		throw Exception(EXLOC, Chain("Cannot get user function"), e);
	    }	    
	}
       	
	bool doDelete=false;
	if ( _pProc->getMasterBlock() != 0 ) // procedure is already in use by this thread ( recursive call ) 
	{
	    _pProc = loadProcedure(_tabSetId, _funcName);
	    doDelete = true;
	}
	    
	ListT<CegoFieldValue> clobRefList;
		
	try 
	{    
	    _pProc->setMasterBlock(pBlock);
	    
	    ListT<CegoProcVar> argList;
	    _pProc->getArgList(argList);
	    
	    ListT<CegoFieldValue> fvl;
	    
	    CegoProcVar *pVar = argList.First();
	    CegoExpr **pExpr = _exprList.First();
	    unsigned pos=1;
	    while ( pVar && pExpr ) 
	    {		    		
		if ( pVar->getVarType() == CegoProcVar::OUTVAR )
		{
		    Chain outVar;
		    (*pExpr)->checkVar(outVar);
		    
		    CegoProcVar *pCheckVar = pBlock->getVarList().Find(CegoProcVar(outVar));
		    if ( pCheckVar == 0 )
		    {
			CegoFieldValue nullVal;
			pBlock->getVarList().Insert(CegoProcVar(outVar, CegoProcVar::BLOCKVAR, NULL_TYPE, 0, 0, nullVal));
		    }
		    // we use fv value to store variable name
		    fvl.Insert( CegoFieldValue(VARCHAR_TYPE, outVar) );
		}
		else // INVAR
		{
		    CegoFieldValue fv = (*pExpr)->evalFieldValue(pFLA, pBlock);
		    
		    if ( fv.getType() == NULL_TYPE )
		    {
			// nothing to to
		    }
		    else if ( pVar->getType() != fv.getType() )		
		    {			
			bool clobCastDone=false;
			if ( pVar->getType() == CLOB_TYPE )
			{
			    if ( CegoQueryHelper::string2Clob(fv, _pTabMng, _tabSetId) )
			    {
				clobCastDone=true;
				clobRefList.Insert(fv);
			    }
			}
			if ( clobCastDone == false )
			{
			    if ( fv.castTo(pVar->getType(), pVar->getDim()) == false )
			    {
				throw Exception(EXLOC, Chain("Mismatched datatype <") 
						+ CEGO_TYPE_MAP[(unsigned)fv.getType()] 
						+ Chain("> in value list for argument ") + Chain(pos) 
						+ " ( expected " 
						+ CEGO_TYPE_MAP[(unsigned)pVar->getType()] + " )");
			    }
			}
		    }
		    
		    fvl.Insert(fv);
		}
		
		pExpr = _exprList.Next();
		pVar = argList.Next();
		pos++;
	    }
	    
	    if ( pVar || pExpr )
	    {	
		Chain msg = Chain("Mismatched parameter count for function ") + _funcName;
		throw Exception(EXLOC, msg);
	    }

	    _pProc->execute(fvl);

	    retVal = _pProc->getRetVal();
	    
	    if ( doDelete )
	    {
		delete _pProc;
		_pProc = 0;
	    }
	    else
	    {
		_pProc->setMasterBlock(0); // indicate proc as not in use
	    }
	}
	catch ( Exception e )
	{
	    CegoFieldValue *pClobRef = clobRefList.First();
	    while ( pClobRef )
	    {	
		if ( pClobRef->getType() == CLOB_TYPE && pClobRef->getValue() != 0 )
		{
		    PageIdType pageId;
		    memcpy(&pageId, pClobRef->getValue(), sizeof(PageIdType));
		    
		    _pTabMng->decreaseClobRef(_tabSetId, pageId);
		}
		pClobRef = clobRefList.Next();
	    }

	    throw Exception(EXLOC, Chain("Cannot eval user function"), e);
	}
	
	return retVal;	
    }
    }
}

CegoProcedure* CegoFunction::loadProcedure(unsigned tabSetId, const Chain& procName) const
{
    CegoProcObject po;
    _pTabMng->getObject(tabSetId, procName, CegoObject::PROCEDURE, po);
    
    Chain loadString = Chain("load ") + po.getProcText();
	
    // cout << "Loading procedure " << loadString << endl;

    CegoProcedure* pProc = 0;

    try
    {
	CegoAction* pPA = _pTabMng->getParser();
	
	pPA->cleanUp();
	pPA->setTableSet(_pTabMng->getDBMng()->getTabSetName(tabSetId));
	pPA->setCommandChain(loadString);

	pPA->parse();

	pPA->execute();

	pProc = pPA->getProcedure(true);

	pProc->enableProcCache(_pTabMng->getDBMng()->getProcCacheEnabled(tabSetId));
    }
    catch ( Exception e ) 
    {
	throw Exception(EXLOC, Chain("Cannot load user function"), e);
    }

    return pProc;
}
    
CegoFunction* CegoFunction::clone(bool isAttrRef)
{
    ListT<CegoExpr*> cloneList;
    
    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	cloneList.Insert( (*pExpr)->clone(isAttrRef));	    
	pExpr = _exprList.Next();
    }
    
    if ( _pTabMng == 0 )
	return ( new CegoFunction(_type, cloneList) );
    else 
    {
	if ( _type == CegoFunction::USERDEFINED )
	{	
	    return ( new CegoFunction(_pTabMng, _tabSetId, _funcName, cloneList) );
	}
	else
	{
	    CegoFunction *pFunc = new CegoFunction(_pTabMng, _tabSetId, _type);
            pFunc->setCounterId(_counterId);
            return pFunc;
	}
    }
}

Chain CegoFunction::getId(CegoProcBlock *pBlock) const
{
    if ( _type ==  CegoFunction::NEXTCOUNT
	 || _type ==  CegoFunction::SETCOUNT
	 || _type ==  CegoFunction::GETCOUNT
	 || _type ==  CegoFunction::RANDINT
	 || _type ==  CegoFunction::RANDSTR
	 || _type ==  CegoFunction::BLOBSIZE
	 || _type ==  CegoFunction::BLOBREF
	 || _type ==  CegoFunction::BLOBSIZE
	 || _type ==  CegoFunction::CLOBREF
	 || _type ==  CegoFunction::CLOBSIZE
	 || _type ==  CegoFunction::CLOB2STR
	 || _type ==  CegoFunction::USERDEFINED )
    {	 
	// we throw an exception here which is catched by CegoSelect::getQueryId, since this is a modyfying query
	throw Exception(EXLOC, Chain(MOD_QUERY_ID));
    }

    Chain argString;

    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	argString += (*pExpr)->getId(pBlock);
	pExpr = _exprList.Next();
    }
    
    Chain funcString = getName();

    Chain s = funcString + Chain("(") + argString + Chain(")");
    return s;   
}

Chain CegoFunction::toChain(unsigned defTabSetId, const Chain& indent) const
{
    Chain argString;

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

    if ( _type == CegoFunction::NEXTCOUNT )
    {
	argString = _counterId;
    }
    else if ( _type == CegoFunction::SETCOUNT )
    {
	argString = _counterId + Chain(",") + argString;
    }
    else if ( _type == CegoFunction::GETCOUNT )
    {
	argString = _counterId;
    }
    
    Chain funcString = getName();
    Chain s = indent + funcString + Chain("(") + argString + Chain(")");

    return s;
}

Chain CegoFunction::dbFormat(CegoDatabaseFormater *pForm) const
{
    return pForm->formatFunction(_type, _exprList, _funcName, _counterId);
}

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

    memcpy( pE, &_type, sizeof(CegoFunction::FunctionType));
    pE = pE + sizeof(CegoFunction::FunctionType);

    if ( _type == CegoFunction::USERDEFINED )
    {
	unsigned len = _funcName.length() - 1;
	memcpy(pE, &len, sizeof(unsigned));
	pE = pE + sizeof(unsigned);
	memcpy(pE, (char*)_funcName, len);
	pE = pE + len; 
    }

    unsigned numExpr = _exprList.Size();

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

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

    memcpy( &_type, pE, sizeof(CegoFunction::FunctionType));
    pE = pE + sizeof(CegoFunction::FunctionType);

    if ( _type == CegoFunction::USERDEFINED )
    {
	unsigned len;
	memcpy( &len, pE, sizeof(unsigned));
	pE = pE + sizeof(unsigned);
	_funcName = Chain((char*)pE, len);
	pE = pE + len;
    }

    unsigned numExpr;
    memcpy( &numExpr, pE, sizeof(unsigned));
    pE = pE + sizeof(unsigned);

    unsigned i=0;
    while ( i < numExpr )
    {
	CegoExpr *pExpr = new CegoExpr(pE);
	pE = pE + pExpr->getEncodingLength();
	_exprList.Insert(pExpr);
	i++;
    }    
}

unsigned CegoFunction::getEncodingLength(CegoProcBlock* pBlock) const
{
    unsigned len = 0;
    
    len += sizeof(CegoFunction::FunctionType);
    if ( _type == CegoFunction::USERDEFINED )
    {
	len += sizeof(unsigned); // size of user funcname
	len += _funcName.length() - 1;
    }
    len += sizeof(unsigned); // numExpr
    
    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	len += (*pExpr)->getEncodingLength(pBlock);
	pExpr = _exprList.Next();
    }
    return len;
}

CegoFunction& CegoFunction::operator = ( const CegoFunction& f)
{
    _type = f._type;
    _exprList = f._exprList;
    _tabSetId = f._tabSetId;
    _pTabMng = f._pTabMng;
    _funcName = f._funcName;
    _pProc = f._pProc;
    return (*this);
}

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


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

    bool doMap=true;
    
    CegoExpr** pExpr = _exprList.First();
    while ( pExpr && doMap )
    {
	CegoExpr* pMapExpr = (*pExpr)->map(viewAlias, exprList);
	if ( pMapExpr )
	    cloneList.Insert(pMapExpr);
	else
	    doMap=false;
	
	pExpr = _exprList.Next();
    }

    if ( doMap == false )
    {
	CegoExpr** pMapExpr = cloneList.First();
	while ( pMapExpr )
	{
	    delete (*pMapExpr);
	    pMapExpr = cloneList.Next();
	}
	return 0;
    }
    
    if ( _pTabMng == 0 )
    {
	return ( new CegoFunction(_type, cloneList) );
    }
    else 
    {
	if ( _type == CegoFunction::USERDEFINED )
	{
	    return ( new CegoFunction(_pTabMng, _tabSetId, _funcName, cloneList) );
	}
	else
	{
	    CegoFunction *pFunc = new CegoFunction(_pTabMng, _tabSetId, _type);
            pFunc->setCounterId(_counterId);
            return pFunc;
	}
    }
}
