///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoTableManager.cc
// -------------------
// Cego table manager class implementation
//                                                         
// Design and Implementation by Bjoern Lemke               
//
// (C)opyright 2000-2025 Bjoern Lemke
//
// IMPLEMENTATION MODULE
//
// Class: CegoTableManager
// 
// Description: The table manager provides are required methods for local tableset operations
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

// base includes
#include <lfcbase/Sleeper.h>
#include <lfcbase/Exception.h>
#include <lfcbase/Timer.h>
#include <lfcbase/SetT.h>
#include <lfcbase/Datetime.h>

// cego includes
#include "CegoDefs.h"
#include "CegoTableManager.h"
#include "CegoTransactionManager.h"
#include "CegoBufferPage.h"
#include "CegoObject.h"
#include "CegoAVLIndexManager.h"
#include "CegoAVLIndexEntry.h"
#include "CegoAVLIndexCursor.h"
#include "CegoBTreeCursor.h"
#include "CegoBTreeManager.h"
#include "CegoTableCursor.h"
#include "CegoAttrCond.h"
#include "CegoXMLdef.h"
#include "CegoTypeConverter.h"
#include "CegoCheckObject.h"
#include "CegoSelect.h"
#include "CegoDbThreadPool.h"

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

extern char __allowDuplicateNull;

CegoTableManager::CegoTableManager(CegoDatabaseManager *pDBMng) : CegoSystemObject(pDBMng)
{
    _pTM = new CegoTransactionManager(this);
    for ( unsigned i=0;i<TABMNG_MAXTABSET; i++)
    {
	_tid[i]=0;
	_tastep[i]=0;
    }
    _encBufLen=0;
    _pEncBuf=0;
    _isAborted = false;
    _autoCommit = true;
    _doAppend = true;
    _isolationLevel = CegoTableManager::READ_COMMITTED;
    _modId = pDBMng->getModId("CegoTableManager");
    _pPool = 0;
}

CegoTableManager::~CegoTableManager()
{
    if ( _pEncBuf )
    {
	free ( _pEncBuf);
    }
    delete _pTM;
}

void CegoTableManager::setThreadId(unsigned long long tid)
{
    _threadId = tid;
}

unsigned long long CegoTableManager::getThreadId() const
{
    return _threadId;
}

void CegoTableManager::setPoolSyncInfo(CegoDbThreadPool *pPool, unsigned thrIdx)
{
    _pPool = pPool;
    _thrIdx = thrIdx;
}

void CegoTableManager::setAppend(bool doAppend)
{
    _doAppend = doAppend;
}

void CegoTableManager::createBasicTableSet(const Chain& tableSet)
{
    _pDBMng->log(_modId, Logger::NOTICE, Chain("Creating basic tableset files ..."));

    unsigned tabSetId =_pDBMng->getTabSetId(tableSet);
    unsigned sysSize = _pDBMng->getSysSize(tableSet);
    unsigned tmpFileId = _pDBMng->getTmpFid(tableSet);
    unsigned tmpSize = _pDBMng->getTmpSize(tableSet);
    Chain dbSysFileName = _pDBMng->getSysFileName(tableSet);
	
    if ( sysSize < TABMNG_HASHSIZE ) 
    {
	Chain msg = Chain("System space must be at least ") + Chain(TABMNG_HASHSIZE) + Chain(" pages ");
	throw Exception(EXLOC, msg);
    }

    if ( tmpSize < TABMNG_HASHSIZE ) 
    {
	Chain msg = Chain("Tmp space must be at least ") + Chain(TABMNG_HASHSIZE) + Chain(" pages ");
	throw Exception(EXLOC, msg);
    }
    
    _pDBMng->log(_modId, Logger::NOTICE, Chain("Initializing sysfile ") + dbSysFileName + Chain(" ..."));

    PageIdType pageOffset;
    
    pageOffset = _pDBMng->getNextPageOffset(sysSize);
    _pDBMng->initDataFile(tabSetId, dbSysFileName, tabSetId,  sysSize, pageOffset, CegoFileHandler::SYSTEMFILE);

    _pDBMng->setSysPageOffset(tabSetId, pageOffset);
    
    _pDBMng->log(_modId, Logger::NOTICE, Chain("Registrating sysfile ") + dbSysFileName + Chain(" ..."));
    _pDBMng->regDataFile(tabSetId, dbSysFileName, tabSetId, _pLockHandle);

    for ( PageIdType i = 0 ; i < TABMNG_HASHSIZE ; i++ )
    {
	_pDBMng->claimPage(pageOffset + i, _pLockHandle);
    }
    
    Chain dbTempFileName = _pDBMng->getTmpFileName(tableSet);
    
    _pDBMng->log(_modId, Logger::NOTICE, Chain("Initializing tempfile ") + dbTempFileName + Chain(" ..."));
    pageOffset = _pDBMng->getNextPageOffset(tmpSize);
    _pDBMng->initDataFile(tabSetId, dbTempFileName, tmpFileId, tmpSize, pageOffset, CegoFileHandler::TEMP);

    _pDBMng->setTempPageOffset(tabSetId, pageOffset);
	
    _pDBMng->log(_modId, Logger::NOTICE, Chain("Registrating tempfile ") + dbTempFileName + Chain(" ..."));
    _pDBMng->regDataFile(tabSetId, dbTempFileName, tmpFileId, _pLockHandle);

    for ( PageIdType i = 0 ; i < TABMNG_HASHSIZE ; i++ )
    {
	_pDBMng->claimPage(pageOffset + i, _pLockHandle);		
    }
        
    _pDBMng->initLogFiles(tableSet, false);
    _pDBMng->setCommittedLSN(tableSet, 0);

    ListT<Chain> dfList;
    ListT<unsigned> fidList;
    ListT<unsigned> sizeList;
    
    _pDBMng->getDataFileInfo(tableSet, Chain(XML_APPFILE_VALUE), dfList, fidList, sizeList);
    
    Chain *pFileName = dfList.First();
    unsigned *pFid = fidList.First();
    unsigned *pSize = sizeList.First();
    
    while ( pFileName && pFid && pSize ) 
    {
	_pDBMng->log(_modId, Logger::NOTICE, Chain("Init datafile ") + *pFileName + Chain(" ..."));	

	pageOffset = _pDBMng->getNextPageOffset(*pSize);
	_pDBMng->initDataFile(tabSetId, *pFileName, *pFid, *pSize, pageOffset, CegoFileHandler::DATAFILE);
	_pDBMng->regDataFile(tabSetId, *pFileName, *pFid, _pLockHandle);
	
	pFileName = dfList.Next();
	pFid = fidList.Next();
	pSize = sizeList.Next();	
    }

    dfList.Empty();
    fidList.Empty();
    sizeList.Empty();

    _pDBMng->getDataFileInfo(tableSet, Chain(XML_SYSFILE_VALUE), dfList, fidList, sizeList);
    
    pFileName = dfList.First();
    pFid = fidList.First();
    pSize = sizeList.First();
    
    while ( pFileName && pFid && pSize ) 
    {
	_pDBMng->log(_modId, Logger::NOTICE, Chain("Init sysfile ") + *pFileName + Chain(" ..."));	

	pageOffset = _pDBMng->getNextPageOffset(*pSize);
	_pDBMng->initDataFile(tabSetId, *pFileName, *pFid, *pSize, pageOffset, CegoFileHandler::SYSTEMFILE);
	_pDBMng->regDataFile(tabSetId, *pFileName, *pFid, _pLockHandle);
	
	pFileName = dfList.Next();
	pFid = fidList.Next();
	pSize = sizeList.Next();	
    }

    dfList.Empty();
    fidList.Empty();
    sizeList.Empty();

    _pDBMng->getDataFileInfo(tableSet, Chain(XML_TEMPFILE_VALUE), dfList, fidList, sizeList);
    
    pFileName = dfList.First();
    pFid = fidList.First();
    pSize = sizeList.First();
    
    while ( pFileName && pFid && pSize ) 
    {	
	_pDBMng->log(_modId, Logger::NOTICE, Chain("Init tempfile ") + *pFileName + Chain(" ..."));	

	pageOffset = _pDBMng->getNextPageOffset(*pSize);
	_pDBMng->initDataFile(tabSetId, *pFileName, *pFid, *pSize, pageOffset, CegoFileHandler::TEMP);
	_pDBMng->regDataFile(tabSetId, *pFileName, *pFid, _pLockHandle);
	
	pFileName = dfList.Next();
	pFid = fidList.Next();
	pSize = sizeList.Next();	
    }
    
    _pDBMng->setTableSetRunState(tableSet, XML_OFFLINE_VALUE);

    if ( _pDBMng->isArchiveMode(tableSet) )
	_pDBMng->nextTableSetBackupBranch(tableSet);

    _pDBMng->doc2Xml();
     
    _pDBMng->log(_modId, Logger::NOTICE, Chain("Tableset ") + tableSet + Chain(" created succesful"));	
}

void CegoTableManager::dropTableSet(const Chain& tableSet)
{
    Chain status = _pDBMng->getTableSetRunState(tableSet);
    
    if ( status == Chain(XML_OFFLINE_VALUE) || status == Chain(XML_CHECKPOINT_VALUE)  )
    {	
	Chain dbSysFileName = _pDBMng->getSysFileName(tableSet); 		
	Chain dbTempFileName = _pDBMng->getTmpFileName(tableSet);

	unsigned tabSetId = _pDBMng->getTabSetId(tableSet);
	_pDBMng->writeAndRemoveTabSet(tabSetId, _pLockHandle);

	File dbSysFile(dbSysFileName);
	
	try
	{           
	    dbSysFile.remove();
	}
	catch ( Exception e )
	{
	    _pDBMng->log(_modId, Logger::NOTICE, Chain("System file ") + dbSysFileName + Chain(" does not exist ( Ignored )"));	
	}
	
	File dbTempFile(dbTempFileName);

	try
	{	    
	    dbTempFile.remove();
	}
	catch ( Exception e )
	{
	    _pDBMng->log(_modId, Logger::NOTICE, Chain("Temp file ") + dbTempFileName + Chain(" does not exist ( Ignored )"));
	}
	
	ListT<Chain> lfList;
	ListT<unsigned> lfsizeList;
	ListT<Chain> statusList;

	_pDBMng->getLogFileInfo(tableSet, lfList, lfsizeList, statusList);
	
	Chain *pLog = lfList.First();

	while ( pLog ) 
	{	    
	    File logFile(*pLog);
	    try
	    {
		logFile.remove();
	    }
	    catch ( Exception e )
	    {
		_pDBMng->log(_modId, Logger::NOTICE, Chain("Log file ") + *pLog + Chain(" does not exist ( Ignored )"));
	    }	
	    pLog = lfList.Next();	    
	}
	
	ListT<Chain> dfList;
	ListT<unsigned> fidList;
	ListT<unsigned> dfsizeList;
	
	_pDBMng->getDataFileInfo(tableSet, Chain(XML_APPFILE_VALUE), dfList, fidList, dfsizeList);
	
	Chain *pFileName = dfList.First();
	
	while ( pFileName ) 
	{	    
	    File dataFile(*pFileName);

	    try
	    {
		dataFile.remove();
	    }
	    catch ( Exception e )
	    {
		_pDBMng->log(_modId, Logger::NOTICE, Chain("Data file ") + *pFileName + Chain(" does not exist ( Ignored )"));
	    }
	    
	    pFileName = dfList.Next();	    
	}

	dfList.Empty();
	fidList.Empty();
	dfsizeList.Empty();

	_pDBMng->getDataFileInfo(tableSet, Chain(XML_TEMPFILE_VALUE), dfList, fidList, dfsizeList);
	
	pFileName = dfList.First();
	
	while ( pFileName ) 
	{	    
	    File dataFile(*pFileName);

	    try
	    {
		dataFile.remove();
	    }
	    catch ( Exception e )
	    {
		_pDBMng->log(_modId, Logger::NOTICE, Chain("Temp file ") + *pFileName + Chain(" does not exist ( Ignored )"));
	    }
	    
	    pFileName = dfList.Next();	    
	}

	dfList.Empty();
	fidList.Empty();
	dfsizeList.Empty();

	_pDBMng->getDataFileInfo(tableSet, Chain(XML_SYSFILE_VALUE), dfList, fidList, dfsizeList);
	
	pFileName = dfList.First();
	
	while ( pFileName ) 
	{	    
	    File dataFile(*pFileName);

	    try
	    {
		dataFile.remove();
	    }
	    catch ( Exception e )
	    {
		_pDBMng->log(_modId, Logger::NOTICE, Chain("Sys file ") + *pFileName + Chain(" does not exist ( Ignored )"));
	    }
	    
	    pFileName = dfList.Next();	    
	}

	// dropping counters
	ListT<Chain> counterList;
	_pDBMng->getCounterList(tabSetId, counterList);
	Chain* pCounter = counterList.First();
	while ( pCounter )
	{
	    _pDBMng->removeCounter(tabSetId, *pCounter);
	    pCounter = counterList.Next();
	}
	
	_pDBMng->setCurrentLSN(tabSetId, 0);
	_pDBMng->setTableSetRunState(tableSet,XML_DEFINED_VALUE);
	_pDBMng->doc2Xml();

	_pDBMng->log(_modId, Logger::NOTICE, Chain("Tableset ") + tableSet + Chain(" dropped"));	
    }
    else
    {
	throw Exception(EXLOC, Chain("Tableset must be in status offline to drop"));
    }
}

void CegoTableManager::reorgTableSet(const Chain& tableSet)
{
    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);
    _pTM->reorgSystemSpace(tabSetId);
}

void CegoTableManager::stopTableSet(const Chain& tableSet, bool archComplete)
{

    Chain runState = _pDBMng->getTableSetRunState(tableSet);

    if ( runState != Chain(XML_ONLINE_VALUE) && runState != Chain(XML_RECOVERY_VALUE) )
    {
	throw Exception(EXLOC, Chain("Tableset must be in status ")
			+ Chain(XML_ONLINE_VALUE)
			+ Chain(" or ")
			+ Chain(XML_RECOVERY_VALUE)
			+ Chain(" to be stopped")); 	
    }

    
    _pDBMng->log(_modId, Logger::NOTICE, Chain("Setting tableset ") + tableSet + Chain(" to offline"));

    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);
	
    // set tableset runstate first to offline to give other pending thread a chance to abort
    _pDBMng->setTableSetRunState(tabSetId, XML_OFFLINE_VALUE);

    _pDBMng->log(_modId, Logger::NOTICE, Chain("Stopping tableset ") + tableSet + Chain(" ..."));
    
    // unsigned long long lsn = _pDBMng->getCurrentLSN(tabSetId);
    // _pDBMng->setCommittedLSN(tabSetId, lsn);
    _pDBMng->writeCheckPoint(tableSet, true, archComplete, _pLockHandle);
    
    
    _pTM->release(tabSetId);
    _pDBMng->writeAndRemoveTabSet(tabSetId, _pLockHandle);
    _pDBMng->stopLog(tabSetId);

    // finally, synchronize lsn with current log lsn ( may be increased during log file switch ) 
     unsigned long long lsn = _pDBMng->getCurrentLSN(tabSetId);
    _pDBMng->setCommittedLSN(tabSetId, lsn);
    
    _pDBMng->doc2Xml();
    _pDBMng->log(_modId, Logger::NOTICE, Chain("Tableset ") + tableSet + Chain(" stopped"));
}

void CegoTableManager::resetTableSet(const Chain& tableSet)
{
    _pDBMng->log(_modId, Logger::NOTICE, Chain("Resetting tableset ") + tableSet + Chain(" ..."));

    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);
    
    unsigned long long lsn = _pDBMng->getCurrentLSN(tabSetId);
    _pDBMng->setCommittedLSN(tabSetId, lsn);
    _pDBMng->writeCheckPoint(tableSet, false, false, _pLockHandle);
    
    _pTM->release(tabSetId);

    if ( _pDBMng->getTableSetRunState(tableSet) == Chain(XML_BACKUP_VALUE) )
    {
	endBackup(tableSet, Chain("Tableset reset"), false); 
    }

    if ( _pDBMng->getTableSetRunState(tableSet) == Chain(XML_ONLINE_VALUE) )
    {    
	_pDBMng->writeAndRemoveTabSet(tabSetId, _pLockHandle);
    }

    _pDBMng->setTableSetRunState(tableSet, XML_OFFLINE_VALUE);
    
    _pDBMng->log(_modId, Logger::NOTICE, Chain("Tableset ") + tableSet + Chain(" reset"));
}

void CegoTableManager::extractTicket(const Chain& tableSet)
{

    Chain tsTicketName = _pDBMng->getTSTicket(tableSet);
    
    File tsTicket(tsTicketName);
    if ( tsTicket.exists()) 
	throw Exception(EXLOC, Chain("Backup tableset ticket exists"));
    
    XMLSuite xml;
    Chain tsTicketData;
    
    Document *pDoc = new Document;	

    try
    {
	pDoc->setAttribute(XML_VERSION_ATTR, XML_VERSION_VALUE);
	pDoc->setDocType(XML_TSTICKET_DOC);
	
	xml.setDocument(pDoc);
	
	Element *pRoot = _pDBMng->getTableSetInfo(tableSet);
	pRoot->setAttribute(XML_BRANCHID_ATTR, _pDBMng->getTableSetBackupBranch(tableSet));
	pDoc->setRootElement(pRoot);
	
	xml.getXMLChain( tsTicketData );
	
	delete pDoc;
    }
    catch ( Exception e )
    {
	delete pDoc;
	throw Exception(EXLOC, Chain("Cannot write ticket data"), e);
    }
    
    tsTicket.open(File::WRITE);
    tsTicket.writeChain(tsTicketData);
    tsTicket.close();

}

void CegoTableManager::beginBackup(const Chain& tableSet, const Chain& msg)
{
    if ( _pDBMng->getTableSetRunState(tableSet) != Chain(XML_ONLINE_VALUE) )
    {
	Chain msg = Chain("Tableset ") + tableSet + Chain(" must be in runstate ONLINE to begin backup mode");
	throw Exception(EXLOC, msg);
    }

    if ( _pDBMng->isArchiveMode(tableSet) == false )
    {
	Chain msg = Chain("Archive not enabled for tableset ") + tableSet;
	throw Exception(EXLOC, msg);
    }

    _pDBMng->log(_modId, Logger::NOTICE, Chain("Begin backup for tableset ") + tableSet);
    
    _pDBMng->writeCheckPoint(tableSet, true, false, _pLockHandle);

    extractTicket(tableSet);
    
    _pDBMng->setTableSetRunState(tableSet, XML_BACKUP_VALUE);
    
    unsigned tabSetId =_pDBMng->getTabSetId(tableSet);
    _pDBMng->setBackup(tabSetId, true);
    unsigned tmpFileId = _pDBMng->getTmpFid(tableSet);	
    _pDBMng->setBackup(tmpFileId, true);
    
    ListT<Chain> dfList;
    ListT<unsigned> fidList;
    ListT<unsigned> sizeList;
    
    _pDBMng->getDataFileInfo(tableSet, Chain(XML_APPFILE_VALUE), dfList, fidList, sizeList);
    
    unsigned *pFid = fidList.First();
    
    while ( pFid ) 
    {
	_pDBMng->setBackup(*pFid, true);
	pFid = fidList.Next();	    
    }
    
    dfList.Empty();
    fidList.Empty();
    sizeList.Empty();
    
    _pDBMng->getDataFileInfo(tableSet, Chain(XML_TEMPFILE_VALUE), dfList, fidList, sizeList);
    
    pFid = fidList.First();
    
    while ( pFid ) 
    {
	_pDBMng->setBackup(*pFid, true);
	pFid = fidList.Next();	    
    }    

    addBUStat(tabSetId, Chain("BEGIN BACKUP"), msg);
}

void CegoTableManager::endBackup(const Chain& tableSet, const Chain& msg, bool keepTicket)
{
    if ( _pDBMng->getTableSetRunState(tableSet) != Chain(XML_BACKUP_VALUE) )
    {
	Chain msg = Chain("Tableset ") + tableSet + Chain(" must be in runstate BACKUP to end backup mode");
	throw Exception(EXLOC, msg);
    }

    if ( _pDBMng->isArchiveMode(tableSet) == false )
    {
	Chain msg = Chain("Archive not enabled for tableset ") + tableSet;
	throw Exception(EXLOC, msg);
    }

    _pDBMng->log(_modId, Logger::NOTICE, Chain("End backup for tableset ") + tableSet);
    
    unsigned tabSetId =_pDBMng->getTabSetId(tableSet);
    _pDBMng->setBackup(tabSetId, false);
    unsigned tmpFileId = _pDBMng->getTmpFid(tableSet);	
    _pDBMng->setBackup(tmpFileId, false);
    
    ListT<Chain> dfList;
    ListT<unsigned> fidList;
    ListT<unsigned> sizeList;
    
    _pDBMng->getDataFileInfo(tableSet, Chain(XML_APPFILE_VALUE), dfList, fidList, sizeList);
    
    unsigned *pFid = fidList.First();
    
    while ( pFid ) 
    {
	_pDBMng->setBackup(*pFid, false);
	pFid = fidList.Next();	    
    }
        
    dfList.Empty();
    fidList.Empty();
    sizeList.Empty();
    
    _pDBMng->getDataFileInfo(tableSet, Chain(XML_TEMPFILE_VALUE), dfList, fidList, sizeList);
    
    pFid = fidList.First();
    
    while ( pFid ) 
    {
	_pDBMng->setBackup(*pFid, false);
	pFid = fidList.Next();	    
    }
    
    CegoLogRecord logRec;    
    CegoLogRecord lr;
    lr.setAction(CegoLogRecord::LOGREC_BUFIN);
    _pDBMng->logIt(tabSetId, lr, _pLockHandle);

    _pDBMng->setTableSetRunState(tableSet, XML_ONLINE_VALUE);
    
    _pDBMng->writeCheckPoint(tableSet, true, false, _pLockHandle);
    
    if ( keepTicket == false)
    {
	Chain tsTicketName = _pDBMng->getTSTicket(tableSet);
	File tsTicket(tsTicketName);
	tsTicket.remove();
    }
    

    addBUStat(tabSetId, Chain("END BACKUP"), msg);
}

void CegoTableManager::resetBUStat(const Chain& tableSet)
{
    unsigned tabSetId =_pDBMng->getTabSetId(tableSet);
    truncateObject(tabSetId, Chain(SYSTAB_BUSTAT_ID), CegoObject::SYSTEM);
}

void CegoTableManager::syncTableSet(const Chain& tableSet, const Chain& msg, const Chain& escCmd, unsigned timeout)
{
    if ( _pDBMng->getTableSetRunState(tableSet) != Chain(XML_ONLINE_VALUE) )
    {
	Chain msg = Chain("Tableset ") + tableSet + Chain(" must be in runstate ONLINE to perform sync");
	throw Exception(EXLOC, msg);
    }

    _pDBMng->writeCheckPoint(tableSet, true, true, _pLockHandle, escCmd, timeout);
    unsigned tabSetId =_pDBMng->getTabSetId(tableSet);
    addBUStat(tabSetId, Chain("EXTERNAL SYNC"), msg);
}

/*
void CegoTableManager::logTo(const Chain& tableSet)
{
 
    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);
  
    _pDBMng->setActiveLogFile(tableSet);
    
    unsigned long long cplsn = _pDBMng->getCommittedLSN(tableSet);
    
    _pDBMng->setCurrentLSN(tabSetId, cplsn);
    _pDBMng->startLog(tabSetId);    
}

*/

void CegoTableManager::addDataFile(const Chain& tableSet, const Chain& type, unsigned fileId, const Chain& dataFile, unsigned fileSize)
{   
    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);
    
    _pDBMng->log(_modId, Logger::NOTICE, Chain("Initializing datafile ") + dataFile + Chain(" ..."));	

    PageIdType pageOffset;    
    pageOffset = _pDBMng->getNextPageOffset(fileSize);

    if ( type == Chain(XML_APPFILE_VALUE) )
    {       
	_pDBMng->initDataFile(tabSetId, dataFile, fileId, fileSize, pageOffset, CegoFileHandler::DATAFILE);
    }
    else if ( type == Chain(XML_TEMPFILE_VALUE) )
    {
	_pDBMng->initDataFile(tabSetId, dataFile, fileId, fileSize, pageOffset, CegoFileHandler::TEMP);
    }
    else if ( type == Chain(XML_SYSFILE_VALUE) )
    {
	_pDBMng->initDataFile(tabSetId, dataFile, fileId, fileSize, pageOffset, CegoFileHandler::SYSTEMFILE);
    }
    
    _pDBMng->regDataFile(tabSetId, dataFile, fileId, _pLockHandle);   

    // with a new datafile, we need new online backup
    if ( _pDBMng->isArchiveMode(tableSet) )
	_pDBMng->nextTableSetBackupBranch(tableSet);
}

void CegoTableManager::setIsolationLevel(IsolationLevel level)
{
    _isolationLevel = level;
}

CegoTableManager::IsolationLevel CegoTableManager::getIsolationLevel() const
{
    return _isolationLevel;
}

void CegoTableManager::setAutoCommit(bool autoCommit)
{
    _autoCommit = autoCommit;
}

bool CegoTableManager::getAutoCommit() const
{
    return _autoCommit;
}

void CegoTableManager::lockTable(unsigned tabSetId, const Chain& tableName)
{
    _pDBMng->useObject(tabSetId, tableName, CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE_WRITE, this);
}

void CegoTableManager::unlockTable(unsigned tabSetId, const Chain& tableName)
{
    _pDBMng->unuseObject(tabSetId, tableName, CegoObject::TABLE, _threadId);
}

void CegoTableManager::beginTransaction(unsigned tabSetId, bool doLog)
{    
    if (_tid[tabSetId] == 0)
    {
	_tid[tabSetId]=_pDBMng->nextTID(tabSetId);
	_tastep[tabSetId]=0;

	if ( doLog )
	{
	    // create log entry
	    CegoLogRecord lr;
	    lr.setAction(CegoLogRecord::LOGREC_BEGIN);
	    lr.setTID(_tid[tabSetId]);	    
	    _pDBMng->logIt(tabSetId, lr, _pLockHandle);
	}
    }
    else
    {
	Chain msg = Chain("Already active transaction on tableset ") + Chain(tabSetId);
	throw Exception(EXLOC, msg);	
    }
}

void CegoTableManager::getTransactionAffectedTables(unsigned tabSetId, SetT<Chain>& tableList)
{
    unsigned long long ctid = _tid[tabSetId];
    if ( ctid > 0 )
	_pTM->getTransactionAffectedTables(tabSetId, ctid, tableList);
}

unsigned long long CegoTableManager::commitTransactionSynced(unsigned tabSetId)
{
    unsigned long long numCommitOp=0;
    
    SetT<Chain> tableList;
    
    getTransactionAffectedTables(tabSetId, tableList);
    
    Chain *pTable;
    
    pTable = tableList.First();
    while ( pTable )
    {	
	_pDBMng->useObject(tabSetId, *pTable, CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE_WRITE, this);
	pTable = tableList.Next();
    }
    
    try
    {	
	numCommitOp = commitTableTransaction(tabSetId, true);
    }
    catch ( Exception e )
    {
	pTable = tableList.First();
	while ( pTable )
	{
	    _pDBMng->unuseObject(tabSetId, *pTable, CegoObject::TABLE);
	    pTable = tableList.Next();
	}
    }
    pTable = tableList.First();
    while ( pTable )
    {
	_pDBMng->unuseObject(tabSetId, *pTable, CegoObject::TABLE);
	pTable = tableList.Next();
    }
    
    return numCommitOp;
}

unsigned long long CegoTableManager::commitTableTransaction(unsigned tabSetId, bool doLog)
{
    if (_tid[tabSetId] != 0)
    {
	unsigned long long ctid = _tid[tabSetId];
	_tid[tabSetId] = 0;
	_tastep[tabSetId] = 0;

	unsigned long long n = _pTM->commitTransaction(tabSetId, ctid);
	
	if ( doLog )
	{
	    // create log entry
	    CegoLogRecord lr;
	    lr.setAction(CegoLogRecord::LOGREC_COMMIT);
	    lr.setTID(ctid);
	    _pDBMng->logIt(tabSetId, lr, _pLockHandle);
	}
	return n;
    }
    else
    {
	// nothing to do
	return 0;
    }
}

unsigned long long CegoTableManager::rollbackTransactionSynced(unsigned tabSetId)
{
    unsigned long long numRollbackOp=0;
	
    SetT<Chain> tableList;
    getTransactionAffectedTables(tabSetId, tableList);
    
    Chain *pTable;
    
    pTable = tableList.First();
    while ( pTable )
    {	
	_pDBMng->useObject(tabSetId, *pTable, CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE_WRITE, this);
	pTable = tableList.Next();
    }
    
    try
    {	
	numRollbackOp = rollbackTableTransaction(tabSetId, true);
    }
    catch ( Exception e )
    {
	pTable = tableList.First();
	while ( pTable )
	{
	    _pDBMng->unuseObject(tabSetId, *pTable, CegoObject::TABLE);
	    pTable = tableList.Next();
	}
    }
    pTable = tableList.First();
    while ( pTable )
    {
	_pDBMng->unuseObject(tabSetId, *pTable, CegoObject::TABLE);
	pTable = tableList.Next();
    }
    
    return numRollbackOp;
}
    
unsigned long long CegoTableManager::rollbackTableTransaction(unsigned tabSetId, bool doLog)
{
    if (_tid[tabSetId] != 0)
    {
	unsigned long long ctid = _tid[tabSetId];
	_tid[tabSetId] = 0;

	unsigned long long n = _pTM->rollbackTransaction(tabSetId, ctid);
	
	if ( doLog )
	{	    
	    // create log entry
	    CegoLogRecord lr;
	    lr.setAction(CegoLogRecord::LOGREC_ABORT);
	    lr.setTID(_tid[tabSetId]);
	    _pDBMng->logIt(tabSetId, lr, _pLockHandle);
	}

	return n;	
    }
    else
    {
	// nothing to do
	return 0;
    }
}

unsigned long long CegoTableManager::getTID(unsigned tabSetId)
{
    return(_tid[tabSetId]);
}

void CegoTableManager::setTAStep(unsigned tabSetId, unsigned long long tastep)
{    
    _tastep[tabSetId]=tastep;
}

unsigned long long CegoTableManager::getTAStep(unsigned tabSetId)
{
    return(_tastep[tabSetId]);
}

void CegoTableManager::setTID(unsigned tabSetId, unsigned long long tid)
{
    _tid[tabSetId] = tid;
}

void CegoTableManager::setTupleInfo(unsigned tabSetId, const CegoDataPointer dp, unsigned long long tid, unsigned long long tastep, CegoTupleState ts)
{
    char *pc;
    unsigned len;

    CegoBufferPage bp;
    claimDataPtrUnlocked(tabSetId, CegoBufferPool::SYNC, dp, pc, len, bp);
        
    CegoQueryHelper::encodeTupleHeader(tid, tastep, ts, pc);

    releaseDataPtrUnlocked(bp, true);
}

void CegoTableManager::getTupleInfo(unsigned tabSetId, const CegoDataPointer dp, unsigned long long& tid, unsigned long long& tastep, CegoTupleState& ts)
{
    char *pc;
    unsigned len;

    CegoBufferPage bp;
    claimDataPtrUnlocked(tabSetId, CegoBufferPool::SYNC, dp, pc, len, bp);

    CegoQueryHelper::decodeTupleHeader(tid, tastep, ts, pc);

    releaseDataPtrUnlocked(bp, true);
}

CegoTableObject CegoTableManager::createDataTable(unsigned tabSetId, const Chain& tableName, CegoObject::ObjectType type, const ListT<CegoField>& fl, bool useColumnId)
{
    if ( type != CegoObject::RBSEG && getTID(tabSetId > 0 ) )
    {
	Chain msg = Chain("create data table in a transaction not allowed"); 
	throw Exception(EXLOC, msg);	
    }
	
    // check duplicate column names

    ListT<CegoField> cfl = fl;
    CegoField* pF = fl.First();
    while (pF)
    {
	unsigned count=0;
	CegoField* pCF = cfl.First();
	while ( pCF )
	{
	    if ( pCF->getAttrName() == pF->getAttrName() )
		count++;	    
	    pCF = cfl.Next();
	}

	if ( count > 1 )
	{
	    Chain msg = Chain("Column ") + pF->getAttrName() + Chain(" multiple defined");
	    throw Exception(EXLOC, msg);
	}
	
	pF = fl.Next();
    }
        
    // define field id's
    unsigned id=1;

    if ( useColumnId == false )
    {
	CegoField* pF = fl.First();
	while (pF)
	{
	    pF->setId(id);
	    pF = fl.Next();
	    if ( pF )
		id++;
	}
    }
    else
    {
	// for plain export and import, we read complete record chunks with id information
	// so for tableimport, we have to restore the previous exported id configuration
	CegoField* pF = fl.First();
	while (pF)
	{
	    if ( id < pF->getId() )
		id = pF->getId();
	    pF = fl.Next();
	}	
    }

    CegoLogRecord lr;
    if ( type != CegoObject::RBSEG )
    {
	lr.setLSN(_pDBMng->nextLSN(tabSetId));	
    }
    
    CegoTableObject oe(tabSetId, type, tableName, fl, tableName);    
    oe.setMaxFid(id);
    createTableObject(oe);
    
    if ( type != CegoObject::RBSEG )
    {
	// create log entry
	lr.setObjectInfo(oe.getName(), oe.getType());
	lr.setAction(CegoLogRecord::LOGREC_CREATE);
	
	char *buf;
	buf = (char*)malloc(oe.getEntrySize());
	if (buf == NULL)
	{
	    throw Exception(EXLOC, Chain("malloc system error"));
	}
	oe.encode(buf);
	lr.setData(buf);
	lr.setDataLen(oe.getEntrySize());

	_pDBMng->logIt(oe.getTabSetId(), lr, _pLockHandle);
	free(buf);
    }

    return oe;
}

void CegoTableManager::alterDataTableSynced(CegoTableObject& oe, const ListT<CegoAlterDesc>& alterList)
{
    _pDBMng->useObject(oe.getTabSetId(), oe.getName(), CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE_WRITE, this);
    
    try
    {
	alterDataTable(oe.getTabSetId(), oe.getName(), CegoObject::TABLE, alterList);
    }
    catch ( Exception e )
    {
	_pDBMng->unuseObject(oe.getTabSetId(), oe.getName(), CegoObject::TABLE);
	throw Exception(EXLOC, Chain("Cannot alter table synced"), e);
    }
    
    _pDBMng->unuseObject(oe.getTabSetId(), oe.getName(), CegoObject::TABLE);
}

void CegoTableManager::alterDataTable(unsigned tabSetId, const Chain& tableName, CegoObject::ObjectType type, const ListT<CegoAlterDesc>& alterList)
{
    if ( getTID(tabSetId) > 0 )
    {
	Chain msg = Chain("alter data table in a transaction not allowed"); 
	throw Exception(EXLOC, msg);	
    }
    
    ListT<CegoTableObject> idxList;
    ListT<CegoBTreeObject> btreeList;
    ListT<CegoKeyObject> keyList;
    ListT<CegoCheckObject> checkList;
    ListT<CegoTriggerObject> triggerList;
    ListT<CegoAliasObject> aliasList;
    unsigned numInvalid;

    getObjectListByTable(tabSetId, tableName, idxList, btreeList, keyList, checkList, triggerList, aliasList, numInvalid);
    
    if ( numInvalid > 0 )
    {
	throw Exception(EXLOC, Chain("Invalid index detected, must be valid for table alter"));    
    }

    // TODO : handle trigger, check and alias objects for table alter operations
    //        for now, we deny altering
    
    if ( checkList.Size() > 0 )
    {
	throw Exception(EXLOC, Chain("Check object detected, must be dropped before table alter"));    
    }
    if ( triggerList.Size() > 0 )
    {
	throw Exception(EXLOC, Chain("Trigger object detected, must be dropped before table alter"));    
    }
    if ( aliasList.Size() > 0 )
    {
	throw Exception(EXLOC, Chain("Alias object detected, must be dropped before table alter"));    
    }
    
    CegoTableObject oe;
    getObject(tabSetId, tableName, type, oe);

    ListT<CegoKeyObject> keyAlterList;
    ListT<CegoTableObject> idxAlterList;
    ListT<CegoBTreeObject> btreeAlterList;
    ListT<CegoKeyObject> keyDropList;
    ListT<CegoTableObject> idxDropList;
    ListT<CegoBTreeObject> btreeDropList;
    ListT<CegoField> alterSchema = oe.getSchema();

    // getting max id
    unsigned maxFid = oe.getMaxFid();
    
    CegoAlterDesc* pAD = alterList.First();
    while (pAD)
    {
	switch ( pAD->getType() )
	{
	case CegoAlterDesc::ADD:
	{	    
	    CegoField* pSF = alterSchema.Find(CegoField(tableName, pAD->getAttrName()));
	    if (pSF)
	    { 
		Chain msg = Chain("Column ") + pAD->getAttrName() + Chain(" already exists");
		throw Exception(EXLOC, msg);
	    }
	    else
	    {
		if ( pAD->getField().isNullable() == false )
		{       	
		    CegoObjectCursor *pOC = getObjectCursor(tabSetId, tableName, tableName, type);
		    unsigned len;
		    CegoDataPointer dp;
		    if ( pOC->getFirst(len, dp) )
		    {			
			delete pOC;
			throw Exception(EXLOC, Chain("Column ") + pAD->getAttrName() + Chain(" cannot be added as not nullable to non-empty table"));
		    }
		    delete pOC;
		}

		maxFid++;
		pAD->getField().setId(maxFid);
		alterSchema.Insert(pAD->getField());		
	    }
	    break;
	}
	case CegoAlterDesc::DROP:
	{	    
	    getKeyAndIdxRef(tabSetId, tableName, pAD->getAttrName(), keyDropList, idxDropList, btreeDropList);
		
	    CegoField* pSF = alterSchema.Find(CegoField(tableName, pAD->getAttrName()));
	    if (pSF)
	    { 
		alterSchema.Remove(*pSF);		
	    }
	    else
	    {
		Chain msg = Chain("Column ") + pAD->getAttrName() + Chain(" does not exist");
		throw Exception(EXLOC, msg);
	    }
	    break;
	}
	case CegoAlterDesc::MODIFY_COLUMN:
	{	  
	    ListT<CegoKeyObject> keyList;
	    ListT<CegoTableObject> idxList;
	    ListT<CegoBTreeObject> btreeList;

	    if ( pAD->getField().isNullable() == false )
	    {
		CegoField* pF = alterSchema.Find(pAD->getField());
		if ( pF )
		{
		    pAD->getField().setId(pF->getId());
		    if ( checkNullValue(tabSetId, tableName, pAD->getField()) )
		    {
			Chain msg = Chain("Null values exist for column ") + pAD->getAttrName();
			throw Exception(EXLOC, msg);
		    }
		}
	    }

	    getKeyAndIdxRef(tabSetId, tableName, pAD->getAttrName(), keyList, idxList, btreeList);

	    // check if any constraints or index object are defined 

	    // check key objects
	    CegoKeyObject* pKey = keyList.First();
	    while ( pKey )
	    {
		if ( (Chain)pKey->getTabName() == (Chain)tableName )
		{		
		    CegoField *pF = pKey->getKeySchema().First();
		    while ( pF )
		    {
			if ( pF->getAttrName() == pAD->getAttrName() )
			{
			    Chain msg = Chain("Column ") + pAD->getAttrName() + Chain(" with foreign key cannot be altered");
			    throw Exception(EXLOC, msg);			    
			}
			pF = pKey->getKeySchema().Next();
		    }
		}
		else if ( (Chain)pKey->getRefTable() == (Chain)tableName )
		{
		    CegoField *pF = pKey->getRefSchema().First();
		    while ( pF )
		    {
			if ( pF->getAttrName() == pAD->getAttrName() )
			{
			    Chain msg = Chain("Column ") + pAD->getAttrName() + Chain(" with foreign key cannot be altered");
			    throw Exception(EXLOC, msg);
			}
			pF = pKey->getRefSchema().Next();
		    }	      
		}
		pKey = keyList.Next();
	    }
	    
	    // columns with avl trees can be modified, so we don't have to check for it

	    // check btree objects
	    CegoBTreeObject* pBTree = btreeList.First();
	    while ( pBTree )
	    {
		CegoField *pF = pBTree->getSchema().First();
		while ( pF )
		{
		    if ( pF->getAttrName() == pAD->getAttrName() )
		    {
			Chain msg = Chain("Column ") + pAD->getAttrName() + Chain(" with btree cannot be altered");
			throw Exception(EXLOC, msg);
		    }
		    pF = pBTree->getSchema().Next();
		}	      
		pBTree = btreeList.Next();
	    }

	    CegoField* pSF = alterSchema.Find(CegoField(tableName, pAD->getAttrName()));
	    if (pSF)
	    {
		unsigned id = pSF->getId();

		// check if field data type could be converted
		if ( pSF->getType() == pAD->getField().getType() )
		{		    
		    *pSF = pAD->getField();
		    pSF->setId(id);
		}
		else
		{
		    Chain msg = Chain("Cannot change column ") + pSF->getAttrName() + Chain(" from type ") + CEGO_TYPE_MAP[pSF->getType()] + Chain(" to ") + CEGO_TYPE_MAP[pAD->getField().getType()];
		    throw Exception(EXLOC, msg);		
		}
		if ( pSF->getLength() > pAD->getField().getLength() )
                {
                    Chain msg = Chain("Cannot shrink column size for ") + pSF->getAttrName() + Chain(" from size  ") + Chain(pSF->getLength()) + Chain(" to ") + Chain(pAD->getField().getLength());
                    throw Exception(EXLOC, msg);
                }
	    }
	    else
	    {
		Chain msg = Chain("Column ") + pAD->getAttrName() + Chain(" does not exist");
		throw Exception(EXLOC, msg);
	    }
	    break;    
	}
	case CegoAlterDesc::MODIFY_DEFAULT:
	{
	    CegoField* pSF = alterSchema.Find(CegoField(tableName, pAD->getAttrName()));
	    if (pSF)
	    {
		CegoFieldValue fv = pAD->getField().getValue();
		
		if ( fv.castTo(pSF->getType(), pSF->getDim()) == false )
		    throw Exception(EXLOC, Chain("Cannot cast from <") 
				    + CEGO_TYPE_MAP[fv.getType()]
				    + Chain("> to <")
				    + CEGO_TYPE_MAP[pSF->getType()]
				    + Chain(">"));
		
		pSF->setValue( fv );
	    }
	    else
	    {
		Chain msg = Chain("Column ") + pAD->getAttrName() + Chain(" does not exist");
		throw Exception(EXLOC, msg);
	    }
	    break;
	}
	case CegoAlterDesc::RENAME:
	{
	    CegoField* pCF = alterSchema.Find(CegoField(tableName, pAD->getAttrName()));
	    if ( pCF )
	    {
		throw Exception(EXLOC, Chain("Attribute ") + pCF->getAttrName() + Chain(" already defined"));
	    }
	       
	    ListT<CegoKeyObject> keyList;
	    ListT<CegoTableObject> idxList;
	    ListT<CegoBTreeObject> btreeList;

	    getKeyAndIdxRef(tabSetId, tableName, pAD->getOldAttrName(), keyList, idxList, btreeList);

	    CegoKeyObject* pKey = keyList.First();
	    while ( pKey )
	    {
		if ( (Chain)pKey->getTabName() == (Chain)tableName )
		{		
		    CegoField *pF = pKey->getKeySchema().First();
		    while ( pF )
		    {
			if ( pF->getAttrName() == pAD->getOldAttrName() )
			{
			    pF->setAttrName(pAD->getAttrName());
			}
			pF = pKey->getKeySchema().Next();
		    }
		}
		else if ( (Chain)pKey->getRefTable() == (Chain)tableName )
		{
		    CegoField *pF = pKey->getRefSchema().First();
		    while ( pF )
		    {
			if ( pF->getAttrName() == pAD->getOldAttrName() )
			{
			    pF->setAttrName(pAD->getAttrName());
			}
			pF = pKey->getRefSchema().Next();
		    }	      
		}
		pKey = keyList.Next();
	    }
	    
	    CegoTableObject* pIdx = idxList.First();
	    while ( pIdx )
	    {
		CegoField *pF = pIdx->getSchema().First();
		while ( pF )
		{
		    if ( pF->getAttrName() == pAD->getOldAttrName() )
		    {			
			pF->setAttrName(pAD->getAttrName());
		    }
		    pF = pIdx->getSchema().Next();
		}	      
		pIdx = idxList.Next();
	    }

	    CegoBTreeObject* pBTree = btreeList.First();
	    while ( pBTree )
	    {
		CegoField *pF = pBTree->getSchema().First();
		while ( pF )
		{
		    if ( pF->getAttrName() == pAD->getOldAttrName() )
		    {			
			pF->setAttrName(pAD->getAttrName());
		    }
		    pF = pBTree->getSchema().Next();
		}	      
		pBTree = btreeList.Next();
	    }
	    
	    keyAlterList += keyList;
	    idxAlterList += idxList;
	    btreeAlterList += btreeList;

	    CegoField* pSF = alterSchema.Find(CegoField(tableName, pAD->getOldAttrName()));
	    if (pSF)
	    { 
		pSF->setAttrName(pAD->getField().getAttrName());
	    }
	    else
	    {
		Chain msg = Chain("Column ") + pAD->getAttrName() + Chain("does not exist");
		throw Exception(EXLOC, msg);
	    }
	    break;
	}       	
	}
	pAD = alterList.Next();
    }

    CegoKeyObject* pDropKey = keyDropList.First();
    while ( pDropKey )
    {
	CegoLogRecord lr;
	lr.setLSN(_pDBMng->nextLSN(tabSetId));	

	removeObject(tabSetId, pDropKey->getName(), pDropKey->getType());
	
	// create log entry
	lr.setObjectInfo(pDropKey->getName(), pDropKey->getType());
	lr.setAction(CegoLogRecord::LOGREC_DROP);    
	lr.setData(0);
	lr.setDataLen(0);
	_pDBMng->logIt(tabSetId, lr, _pLockHandle);
	
	pDropKey = keyDropList.Next();
    }

    CegoTableObject* pDropIdx = idxDropList.First();
    while ( pDropIdx )
    {
	CegoLogRecord lr;
	lr.setLSN(_pDBMng->nextLSN(tabSetId));	

	removeObject(tabSetId, pDropIdx->getName(), pDropIdx->getType());
	
	// create log entry
	lr.setObjectInfo(pDropIdx->getName(), pDropIdx->getType());
	lr.setAction(CegoLogRecord::LOGREC_DROP);    
	lr.setData(0);
	lr.setDataLen(0);
	_pDBMng->logIt(tabSetId, lr, _pLockHandle);
		
	pDropIdx = idxDropList.Next();
    }

    CegoBTreeObject* pDropBTree = btreeDropList.First();
    while ( pDropBTree )
    {
	CegoLogRecord lr;
	lr.setLSN(_pDBMng->nextLSN(tabSetId));	

	removeObject(tabSetId, pDropBTree->getName(), pDropBTree->getType());
	
	// create log entry
	lr.setObjectInfo(pDropBTree->getName(), pDropBTree->getType());
	lr.setAction(CegoLogRecord::LOGREC_DROP);    
	lr.setData(0);
	lr.setDataLen(0);
	_pDBMng->logIt(tabSetId, lr, _pLockHandle);
		
	pDropBTree = btreeDropList.Next();
    }

    CegoKeyObject* pKey = keyAlterList.First();
    while ( pKey )
    {
	CegoLogRecord lr;
	lr.setLSN(_pDBMng->nextLSN(tabSetId));	

	alterKeyObject(tabSetId, tableName, *pKey);

	// create log entry 
	lr.setObjectInfo(pKey->getName(), pKey->getType());
	lr.setAction(CegoLogRecord::LOGREC_ALTER);
	
	char *buf;
	buf = (char*)malloc(pKey->getEntrySize());
	if (buf == NULL)
	{
	    throw Exception(EXLOC, Chain("malloc system error"));
	}
    
	pKey->encode(buf);
	lr.setData(buf);
	lr.setDataLen(pKey->getEntrySize());

	_pDBMng->logIt(tabSetId, lr, _pLockHandle);
	
	free(buf);

	pKey = keyAlterList.Next();
    }

    CegoTableObject* pIdx = idxAlterList.First();
    while ( pIdx )
    {
	CegoLogRecord lr;
	lr.setLSN(_pDBMng->nextLSN(tabSetId));	

	alterTableObject(tabSetId, pIdx->getName(), pIdx->getType(), *pIdx);

	// create log entry 
	lr.setObjectInfo(pIdx->getName(), pIdx->getType());
	lr.setAction(CegoLogRecord::LOGREC_ALTER);
	
	char *buf;
	buf = (char*)malloc(pIdx->getEntrySize());
	if (buf == NULL)
	{
	    throw Exception(EXLOC, Chain("malloc system error"));
	}

	pIdx->encode(buf);
	lr.setData(buf);
	lr.setDataLen(pIdx->getEntrySize());

	_pDBMng->logIt(tabSetId, lr, _pLockHandle);
	
	free(buf);

	pIdx = idxAlterList.Next();
    }

    CegoBTreeObject* pBTree = btreeAlterList.First();
    while ( pBTree )
    {
	CegoLogRecord lr;
	lr.setLSN(_pDBMng->nextLSN(tabSetId));	

	alterBTreeObject(tabSetId, pBTree->getName(), pBTree->getType(), *pBTree);

	// create log entry
	lr.setObjectInfo(pBTree->getName(), pBTree->getType());
	lr.setAction(CegoLogRecord::LOGREC_ALTER);
	
	char *buf;
	buf = (char*)malloc(pBTree->getEntrySize());
	if (buf == NULL)
	{
	    throw Exception(EXLOC, Chain("malloc system error"));
	}

	pBTree->encode(buf);
	lr.setData(buf);
	lr.setDataLen(pBTree->getEntrySize());

	_pDBMng->logIt(tabSetId, lr, _pLockHandle);
	
	free(buf);

	pBTree = btreeAlterList.Next();
    }

    CegoTableObject aoe;
    getObject(tabSetId, tableName, type, aoe);
    aoe.setSchema(alterSchema);
    aoe.setMaxFid(maxFid);

    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));	

    alterTableObject(tabSetId, tableName, type, aoe);
    
    // create log entry 
    lr.setObjectInfo(aoe.getName(), aoe.getType());
    lr.setAction(CegoLogRecord::LOGREC_ALTER);

    char *buf;
    buf = (char*)malloc(aoe.getEntrySize());
    if (buf == NULL)
    {
	throw Exception(EXLOC, Chain("malloc system error"));
    }
    
    aoe.encode(buf);
    lr.setData(buf);
    lr.setDataLen(aoe.getEntrySize());

    _pDBMng->logIt(aoe.getTabSetId(), lr, _pLockHandle);

    free(buf);
}

void CegoTableManager::renameObject(unsigned tabSetId, const Chain& objName, CegoObject::ObjectType type, const Chain& newObjName)
{
    switch ( type )
    {
    case CegoObject::TABLE:
    {
	renameTable(tabSetId, objName, newObjName);
	break;
    }
    case CegoObject::AVLTREE:
    case CegoObject::UAVLTREE:
    case CegoObject::PAVLTREE:
    {
	renameIndex(tabSetId, objName, type, newObjName);
	break;
    }
    case CegoObject::BTREE:
    case CegoObject::UBTREE:
    case CegoObject::PBTREE:
    {
	renameBTree(tabSetId, objName, type, newObjName);
	break;
    }
    case CegoObject::FKEY:
    {
	renameKey(tabSetId, objName, newObjName);
	break;
    }
    case CegoObject::CHECK:
    {
	renameCheck(tabSetId, objName, newObjName);
	break;
    }
    case CegoObject::RBSEG:
    {
	renameRBO(tabSetId, objName, newObjName);
	break;
    }
    case CegoObject::TRIGGER:
    {
	renameTrigger(tabSetId, objName, newObjName);
	break;       
    }
    case CegoObject::SYSTEM:
    case CegoObject::JOIN:
    case CegoObject::ALIAS:
    case CegoObject::UNDEFINED:
    case CegoObject::PROCEDURE:
    case CegoObject::VIEW:
	throw Exception(EXLOC, Chain("Renaming for object type not supported"));
    }
}

void CegoTableManager::renameTable(unsigned tabSetId, const Chain& tableName, const Chain& newTableName)
{
    CegoTableObject oe;
    getObject(tabSetId, tableName, CegoObject::TABLE, oe);

    CegoObject::ObjectType type = oe.getType();
    oe.setName(newTableName);
    oe.setTabName(newTableName);    

    ListT<CegoTableObject> idxList;
    ListT<CegoBTreeObject> btreeList;
    ListT<CegoKeyObject> keyList;
    ListT<CegoCheckObject> checkList;
    ListT<CegoTriggerObject> triggerList;
    ListT<CegoAliasObject> aliasList;
    unsigned numInvalid;

    getObjectListByTable(tabSetId, tableName, idxList, btreeList, keyList, checkList, triggerList, aliasList, numInvalid);
    
    if ( numInvalid > 0 )
    {
	throw Exception(EXLOC, Chain("Invalid index detected, must be valid for table renaming"));    
    }

    CegoTableObject *pIO = idxList.First();
    while ( pIO )
    {
	if ( pIO->getType() == CegoObject::AVLTREE 
	     || pIO->getType() == CegoObject::UAVLTREE
	     || pIO->getType() == CegoObject::PAVLTREE )
	{
	    CegoTableObject idx;
	    getObject(tabSetId, pIO->getName(), pIO->getType(), idx);
	    idx.setTabName( newTableName );
	
	    alterTableObject(tabSetId, pIO->getName(), pIO->getType(), idx);   
	}
	pIO = idxList.Next();
    }

    CegoBTreeObject *pBTO = btreeList.First();
    while ( pBTO )
    {
	if ( pBTO->getType() == CegoObject::BTREE
	     || pBTO->getType() == CegoObject::UBTREE
	     || pBTO->getType() == CegoObject::PBTREE )
	{
	    CegoBTreeObject btree;
	    getObject(tabSetId, pBTO->getName(), pBTO->getType(), btree);
	    btree.setTabName( newTableName );

	    alterBTreeObject(tabSetId, pBTO->getName(), pBTO->getType(), btree);   
	}
	pBTO = btreeList.Next();
    }

    CegoKeyObject *pKO = keyList.First();
    while ( pKO )
    {
	CegoKeyObject keyObj;
	getObject(tabSetId, pKO->getName(), pKO->getType(), keyObj);
	keyObj.setTabName( newTableName );
	
	alterKeyObject(tabSetId, pKO->getName(), keyObj);

	pKO = keyList.Next();
    }

    CegoCheckObject *pCO = checkList.First();
    while ( pCO )
    {
	CegoCheckObject checkObj;
	getObject(tabSetId, pCO->getName(), pCO->getType(), checkObj);
	checkObj.setTabName( newTableName );
	
	alterCheckObject(tabSetId, pCO->getName(), checkObj);

	pCO = checkList.Next();
    }

    CegoTriggerObject *pTO = triggerList.First();
    while ( pTO )
    {
	CegoTriggerObject triggerObj;
	getObject(tabSetId, pTO->getName(), pTO->getType(), triggerObj);
	triggerObj.setTabName( newTableName );
	
	alterTriggerObject(tabSetId, pTO->getName(), triggerObj);

	pTO = triggerList.Next();
    }

    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));	

    alterTableObject(tabSetId, tableName, type, oe);

    // create log entry 
    lr.setObjectInfo(tableName, type);
    lr.setAction(CegoLogRecord::LOGREC_RENAME);

    lr.setData((char*)newTableName);
    lr.setDataLen(newTableName.length());

    _pDBMng->logIt(oe.getTabSetId(), lr, _pLockHandle);
}

void CegoTableManager::renameIndex(unsigned tabSetId, const Chain& idxName, CegoObject::ObjectType type, const Chain& newIdxName)
{
    if ( type != CegoObject::PAVLTREE && type !=  CegoObject::UAVLTREE && type != CegoObject::AVLTREE )
	throw Exception(EXLOC, Chain("Invalid index type"));	
    
    CegoTableObject oe;
    getObject(tabSetId, idxName, type, oe);

    oe.setName(newIdxName);

    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));	

    alterTableObject(tabSetId, idxName, type, oe);

    // create log entry 
    lr.setObjectInfo(idxName, type);
    lr.setAction(CegoLogRecord::LOGREC_RENAME);
    lr.setData((char*)newIdxName);
    lr.setDataLen(newIdxName.length());

    _pDBMng->logIt(oe.getTabSetId(), lr, _pLockHandle);
}

void CegoTableManager::renameBTree(unsigned tabSetId, const Chain& btreeName, CegoObject::ObjectType type, const Chain& newBTreeName)
{
    if ( type != CegoObject::PBTREE && type !=  CegoObject::UBTREE && type != CegoObject::BTREE )
	throw Exception(EXLOC, Chain("Invalid btree type"));	
    
    CegoBTreeObject btoe;
    getObject(tabSetId, btreeName, type, btoe);

    btoe.setName(newBTreeName);

    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));	

    alterBTreeObject(tabSetId, btreeName, type, btoe);

    // create log entry 
    lr.setObjectInfo(btreeName, type);
    lr.setAction(CegoLogRecord::LOGREC_RENAME);
    lr.setData((char*)newBTreeName);
    lr.setDataLen(newBTreeName.length());

    _pDBMng->logIt(btoe.getTabSetId(), lr, _pLockHandle);
}

void CegoTableManager::renameKey(unsigned tabSetId, const Chain& keyName, const Chain& newKeyName)
{
    CegoKeyObject oe;
    getObject(tabSetId, keyName, CegoObject::FKEY, oe);

    oe.setName(newKeyName);

    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));	

    alterKeyObject(tabSetId, keyName, oe);

    // create log entry 
    lr.setObjectInfo(keyName, CegoObject::FKEY);
    lr.setAction(CegoLogRecord::LOGREC_RENAME);

    lr.setData((char*)newKeyName);
    lr.setDataLen(newKeyName.length());

    _pDBMng->logIt(tabSetId, lr, _pLockHandle);
}

void CegoTableManager::renameRBO(unsigned tabSetId, const Chain& rboName, const Chain& newRboName)
{
    CegoTableObject rbo;
    getObject(tabSetId, rboName, CegoObject::RBSEG, rbo);

    rbo.setName(newRboName);
        
    alterTableObject(tabSetId, rboName, CegoObject::RBSEG, rbo);

    // no need to create log entry
}

void CegoTableManager::renameCheck(unsigned tabSetId, const Chain& checkName, const Chain& newCheckName)
{
    CegoCheckObject oe;
    getObject(tabSetId, checkName, CegoObject::CHECK, oe);

    oe.setName(newCheckName);

    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));	

    alterCheckObject(tabSetId, checkName, oe);

    // create log entry 
    lr.setObjectInfo(checkName, CegoObject::CHECK);
    lr.setAction(CegoLogRecord::LOGREC_RENAME);
    lr.setData((char*)newCheckName);
    lr.setDataLen(newCheckName.length());

    _pDBMng->logIt(tabSetId, lr, _pLockHandle);
}

void CegoTableManager::renameTrigger(unsigned tabSetId, const Chain& triggerName, const Chain& newTriggerName)
{
    CegoTriggerObject to;
    getObject(tabSetId, triggerName, CegoObject::TRIGGER, to);

    to.setName(newTriggerName);

    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));	

    alterTriggerObject(tabSetId, triggerName, to);

    // create log entry 
    lr.setObjectInfo(triggerName, CegoObject::TRIGGER);
    lr.setAction(CegoLogRecord::LOGREC_RENAME);
    lr.setData((char*)newTriggerName);
    lr.setDataLen(newTriggerName.length());

    _pDBMng->logIt(tabSetId, lr, _pLockHandle);
}

void CegoTableManager::reorgObjectSynced(unsigned tabSetId, const Chain& objName, CegoObject::ObjectType type)
{
    _pDBMng->useObject(tabSetId, objName, type, CegoDatabaseManager::EXCLUSIVE_WRITE, this);
    
    try
    {	
	reorgObject(tabSetId, objName, type);	
    }
    catch ( Exception e )
    {
	_pDBMng->unuseObject(tabSetId, objName, type);
    }
    _pDBMng->unuseObject(tabSetId, objName, type);
}

void CegoTableManager::reorgTable(unsigned tabSetId, const Chain& tableName)
{
    reorgObject(tabSetId, tableName, CegoObject::TABLE);
}

void CegoTableManager::invalidateIndexForTable(unsigned tabSetId, const Chain& tableName)
{
    ListT<CegoTableObject> idxList;
    ListT<CegoBTreeObject> btreeList;
    ListT<CegoKeyObject> keyList;
    ListT<CegoCheckObject> checkList;
    ListT<CegoTriggerObject> triggerList;
    ListT<CegoAliasObject> aliasList;
    unsigned numInvalid;

    getObjectListByTable(tabSetId, tableName, idxList, btreeList, keyList, checkList, triggerList, aliasList, numInvalid);

    CegoTableObject *pIdx = idxList.First();
    while ( pIdx )
    {
	invalidateObject(tabSetId, pIdx->getName(), pIdx->getType());
	pIdx = idxList.Next();
    }

    CegoBTreeObject *pBTree = btreeList.First();
    while ( pBTree )
    {
	invalidateObject(tabSetId, pBTree->getName(), pBTree->getType());
	pBTree = btreeList.Next();
    }
}

void CegoTableManager::insertDataTable(CegoTableObject& oe, ListT<CegoField>& fvl, CegoDataPointer& dp, bool doLogging, bool flushLog)
{
    ListT<CegoTableObject> idxList;
    ListT<CegoBTreeObject> btreeList;
    ListT<CegoKeyObject> keyList;
    ListT<CegoCheckObject> checkList;
    ListT<CegoTriggerObject> triggerList;
    ListT<CegoAliasObject> aliasList;
    unsigned numInvalid;

    bool doAppend = false;

    if ( oe.getType() == CegoObject::TABLE )
    {
	getObjectListByTable(oe.getTabSetId(), oe.getName(), idxList, btreeList, keyList,
			     checkList, triggerList, aliasList, numInvalid);
	if ( numInvalid > 0 )
	{	
	    // for ongoing transactions, we don't support online index build up
	    if ( getTID(oe.getTabSetId() != 0 ))
	    {
		throw Exception(EXLOC, Chain("Invalid index detected, must be valid for transactions"));
	    }	
	    doAppend = true;
	}
	else
	{
	    doAppend = _doAppend;
	}
    }
    
    CegoDataPointer sysEntry;
    Chain virginIndex;
    insertDataTable(oe, fvl, idxList, btreeList, keyList, checkList, sysEntry, virginIndex, dp, doLogging, doAppend, true, flushLog);
}

void CegoTableManager::insertDataTable(CegoTableObject& oe, ListT<CegoField>& nfvl, 
				       const ListT<CegoTableObject>& idxList, 
				       const ListT<CegoBTreeObject>& btreeList, 
				       const ListT<CegoKeyObject>& keyList, 
				       const ListT<CegoCheckObject>& checkList,
				       const CegoDataPointer& sysEntry,
				       const Chain& virginIndex,
				       CegoDataPointer& dp, bool doLogging, bool doAppend, bool increaseStep, bool flushLog)
{

    CegoLogRecord lr;


    /*
    if ( oe.getType() == CegoObject::TABLE && doLogging == true )
    {
	lr.setLSN(_pDBMng->nextLSN(oe.getTabSetId()));
    }
    */

    // nextTAStep, just done for explicit insert ( disabled for use by updateTuple method, since TA step is already increased by embedding update method )
    if ( increaseStep )
    {
	if ( getTID(oe.getTabSetId()) != 0 ) 
	    _tastep[oe.getTabSetId()]++;
    }
    
    CegoDataPointer nil;   

    dp = nil;

    unsigned long long tid = 0;
    unsigned long long tastep = 0;
    CegoTupleState ts = COMMITTED;

    unsigned idxInsertCount=0;
    unsigned btreeInsertCount=0;

    /////////////////////////////////////////////
    // Step 1 : Setting ids and check null values
    /////////////////////////////////////////////
    // after setting ids, the fvl must be sorted in terms of the id
    
    CegoField* pF = nfvl.First();
    while (pF)
    {	
	CegoField* pSF = oe.getSchema().Find(CegoField(oe.getName(), pF->getAttrName()));
	
	// check for allowed null values
	if ( pF->getValue().getType() == NULL_TYPE && pSF->isNullable() == false )
	{
	    throw Exception(EXLOC, Chain("Invalid null value"));
	}
	
	if ( pSF )
	{
	    pF->setId(pSF->getId());
	}
	    
	pF = nfvl.Next();
    }
    
    ListT<CegoField> fvl;
    
    pF = nfvl.First();
    unsigned maxId=0;
    while ( pF )
    {
	if ( pF->getId() > maxId )
	    maxId = pF->getId();
	pF = nfvl.Next();
    }

    for ( unsigned id=0; id<=maxId; id++ )
    {
	CegoField *pF = nfvl.First();
	while ( pF )
	{
	    if ( pF->getId() == id )
	    {
		fvl.Insert(*pF);
		pF = 0;
	    }
	    else
	    {
		pF = nfvl.Next();
	    }
	}
    }

    unsigned long long cpCount = _pDBMng->getCPCount();

    unsigned encLen;
    
    try 
    {             
	/////////////////////////////////////////////
	// Step 2 : Insert table data
	/////////////////////////////////////////////

	if ( oe.getType() == CegoObject::TABLE )
	{	    
	    tid = getTID(oe.getTabSetId());
	    tastep = getTAStep(oe.getTabSetId());
	    if ( tid > 0 )
		ts = CegoTupleState::INSERTED;
	}
	
	encLen = CegoQueryHelper::encodeFVL(tid, tastep, ts, fvl, _pEncBuf, _encBufLen);
	
	unsigned numTries=0;
	while ( dp == nil )
	{
	    try
	    {
		if ( sysEntry == nil )
		{
		    dp = insertData(oe, _pEncBuf, encLen, doAppend);
		}
		else
		{
		    dp = insertData(sysEntry, oe, _pEncBuf, encLen, doAppend);
		}
	    }
	    catch ( Exception e)
	    {
		Chain msg;
		e.pop(msg);
		_pDBMng->log(_modId, Logger::NOTICE, Chain("Retry insert after :  ") +  msg);
		
		if ( numTries == LCKMNG_NUMLOCKTRIES )
		{
		    throw Exception(EXLOC, msg);
		}
		numTries++;
	    }
	}

	///////////////////////////////////
	// Step 3 : check key contraints //
	///////////////////////////////////
	
	// Note: since fkeys can refer to a primary key inside the same table and the same row, 
	// this must be done as the second step
	    
	if ( ! keyList.isEmpty() )
	{
	    CegoKeyObject* pKey = keyList.First();
	    while ( pKey )
	    {
		if ( (Chain)pKey->getTabName() == (Chain)oe.getName() )
		{		    
		    Chain idxName = pKey->getRefTable() + Chain(TABMNG_PBTREE_SUFFIX);
		    bool hasBTree = true;
		    ListT<CegoField> rfl;
		    ListT<CegoField> ifl;

		    try
		    {
			if ( objectExists(oe.getTabSetId(), idxName, CegoObject::PBTREE ))
			{
			    CegoBTreeObject pbt;
			    getObject(oe.getTabSetId(), idxName, CegoObject::PBTREE, pbt);			
			    rfl = pbt.getSchema();
			    ifl = pbt.getSchema();
			}
			else  
			{
			    idxName = pKey->getRefTable() + Chain(TABMNG_PIDX_SUFFIX);
			    hasBTree = false;
			    
			    CegoTableObject poe;
			    getObject(oe.getTabSetId(), idxName, CegoObject::PAVLTREE, poe);			
			    rfl = poe.getSchema();
			    ifl = poe.getSchema();			
			}
		    }
		    catch ( Exception e )
		    {
			Chain msg = Chain("Primary index or btree required for insert operation");
			throw Exception(EXLOC, msg);
		    }
			
		    ListT<CegoField> kfl = pKey->getKeySchema();
		    CegoField *pKF = kfl.First();
		    while ( pKF )
		    {
			CegoField *pDF = fvl.Find(*pKF);
			if ( pDF )
			{
			    pKF->setValue(pDF->getValue());
			}
			else
			{
			    Chain msg = Chain("Cannot access key attribute <") + pKF->getAttrName() + Chain(">");
			    throw Exception(EXLOC, msg);			    
			}
			pKF = kfl.Next();
		    }
		    
		    CegoField *pRF = rfl.First();
		    pKF = kfl.First();
		    
		    CegoAttrCond ac;
		    
		    while ( pKF && pRF )
		    {
			ac.add(CegoAttrComp(pRF->getTableAlias(), pRF->getAttrName(), EQUAL, pKF->getValue()));
			pRF = rfl.Next();
			pKF = kfl.Next();
		    }

		    bool hasTuple;
		    
		    if ( hasBTree )
		    {
			CegoBTreeCursor btc(this, oe.getTabSetId(), idxName, CegoObject::PBTREE, &ac, false, false);
			CegoDataPointer dp;
			hasTuple = btc.getFirst(ifl, dp);			
		    }
		    else
		    {
			CegoAVLIndexCursor ic(this, oe.getTabSetId(), idxName, CegoObject::PAVLTREE, &ac, false, false);
			CegoDataPointer dp;
			hasTuple = ic.getFirst(ifl, dp);
		    }

		    if ( hasTuple == false )
		    {
			// check for self refering tables, if the new inserted tuple can satisfy the constraint

			if ( (Chain)pKey->getTabName() == (Chain)pKey->getRefTable() )
			{
			    bool keyMatch = true;
			    pKF = kfl.First();
			    pRF = rfl.First();
			    while ( pKF && keyMatch )
			    {
				CegoField *pF = nfvl.Find(CegoField(Chain(), pRF->getAttrName()));
				if ( pF )
				{
				    if ( ! ( (CegoFieldValue)pKF->getValue() == (CegoFieldValue)pF->getValue()) )
				    {
					keyMatch=false;
				    }
				}
				else
				{
				    Chain msg = Chain("Cannot access key attribute <") + pRF->getAttrName() + Chain(">");
				    throw Exception(EXLOC, msg);				    
				}
				pKF = kfl.Next();
				pRF = rfl.Next();
			    }

			    if ( keyMatch == false )
			    {
				Chain msg = Chain("Missing foreign key value in reference btree <") + idxName + Chain(">");
				throw Exception(EXLOC, msg);			
			    }
			}
			else
			{
			    Chain msg = Chain("Missing foreign key value in reference btree <") + idxName + Chain(">");
			    throw Exception(EXLOC, msg);
			}			
		    }
		}
		pKey = keyList.Next();
	    }
	}

	///////////////////////////////////
	// Step 4 : Check check constraints
	///////////////////////////////////
	
	if ( ! checkList.isEmpty() )
	{
	    CegoCheckObject* pCheck = checkList.First();
	    while ( pCheck )
	    {	      
		// cout << "======= Check Constraint .." << endl;
		pCheck->getPredDesc()->clearAttrCache();
		// cout << "after clear attr cache" << endl;
		
		// we need to create an additional reference to call evalPredicate
		ListT<CegoField>* xfl[2];
		xfl[0] = &fvl;
		xfl[1] = 0;	     
		
		if ( pCheck->getPredDesc()->eval(0, 0, xfl, 0, 0) == false )
		{
		    Chain msg = Chain("Check constraint ") + pCheck->getName() + Chain(" violated");
		    throw Exception(EXLOC, msg);
		}
		
		pCheck = checkList.Next();
	    }
	}
	
	///////////////////////////////////
	// Step 5: Add index ref         //
	///////////////////////////////////
	       	
	CegoTableObject* pOE = idxList.First();

	idxInsertCount=0;
	while (pOE)
	{
	    if (pOE->getName() != virginIndex &&
		pOE->isValid() &&
		( pOE->getType() == CegoObject::AVLTREE 
		  || pOE->getType() == CegoObject::UAVLTREE 
		  || pOE->getType() == CegoObject::PAVLTREE ) )
	    {	
		char p[TABMNG_MAXINDEXVALUE];
		unsigned len = TABMNG_MAXINDEXVALUE;
		unsigned idxLen;
		CegoDataPointer ritp;
		
		extractIndexValue(fvl, pOE->getSchema(), p, len, idxLen);
		
		CegoDataPointer nil;

		CegoAVLIndexManager idxMng(this);
		idxMng.insertNativeIndexTable(*pOE,
					      nil, 
					      dp, 
					      p,
					      idxLen, 
					      getTID(oe.getTabSetId()), 					      
					      doAppend,
					      ritp);
		idxInsertCount++;
	    }
	    pOE = idxList.Next();
	}

	///////////////////////////////////
	// Step 6: Add btree ref         //
	///////////////////////////////////
	       	
	CegoBTreeObject* pBTO = btreeList.First();

	btreeInsertCount=0;
	while (pBTO)
	{	    
	    if (pBTO->getName() != virginIndex &&
		pBTO->isValid() &&
		( pBTO->getType() == CegoObject::BTREE 
		  || pBTO->getType() == CegoObject::UBTREE 
		  || pBTO->getType() == CegoObject::PBTREE ) )
	    {
		CegoBTreeValue iv;

		iv.valueFromSchema(fvl, pBTO->getSchema());

		CegoBTreeManager btreeMng(this, pBTO);
		
		btreeMng.insertBTreeWithCommit(dp,
				     iv,
				     getTID(oe.getTabSetId()));
		btreeInsertCount++;
	    }
	    pBTO = btreeList.Next();
	}
	
	/////////////////////////////////
	// Step 7: Make rollback entry  //
	/////////////////////////////////
	// any exceptions also have to be catched ( e.g. temp space expired )
	// to rollback the complete insert operation
	
	if (oe.getType() == CegoObject::TABLE && getTID(oe.getTabSetId()) != 0)
	{
	    _pTM->newRBEntry(oe.getTabSetId(), getTID(oe.getTabSetId()), dp.getPageId(), dp.getOffset(), oe.getName());
	} 	
    }
    catch ( Exception e)
    {
	if ( dp != nil )
	{
	    deleteData(oe.getType(), oe.getTabSetId(), dp);	   

	    /* if a checkpoint has occured during teh insert procedure, we have to sync again
	       to have consistent data on disk */

	    if ( _pDBMng->getCPCount() > cpCount )
	    {			    
		_pDBMng->log(_modId, Logger::NOTICE, Chain("Forced checkpoint by insertDataTable"));
		_pDBMng->writeCheckPoint(oe.getTabSetId(), true, Chain(), 0,  _pLockHandle);
	    }
	    
	    unsigned i=0;
	    CegoTableObject* pOE = idxList.First();
	    while (pOE && i < idxInsertCount)
	    {		
		if (pOE->getName() != virginIndex &&
		    pOE->isValid() &&
		    ( pOE->getType() == CegoObject::AVLTREE 
		      || pOE->getType() == CegoObject::UAVLTREE 
		      || pOE->getType() == CegoObject::PAVLTREE ) )
		{		    		    
		    char p[TABMNG_MAXINDEXVALUE];
		    unsigned len = TABMNG_MAXINDEXVALUE;
		    unsigned idxLen;
		    
		    extractIndexValue(fvl, pOE->getSchema(), p, len, idxLen);
		    
		    // cout << "Deleting index for " << pOE->getName() << " of len " << idxLen << endl;		       
		    CegoAVLIndexManager idxMng(this);
		    idxMng.deleteIndexTable(oe.getTabSetId(), oe.getName(), oe.getType(), 
						pOE->getName(), pOE->getType(), pOE->getSchema(), dp, p, idxLen);		    
		    i++;
		}
		pOE = idxList.Next();
	    }

	    CegoBTreeObject* pBTO = btreeList.First();

	    i=0;
	    while (pBTO && i < btreeInsertCount )
	    {		
		if (pBTO->getName() != virginIndex &&
		    pBTO->isValid() &&
		    ( pBTO->getType() == CegoObject::BTREE 
		      || pBTO->getType() == CegoObject::UBTREE 
		      || pBTO->getType() == CegoObject::PBTREE ) )
		{		    		    
		    CegoBTreeValue btv;
		    btv.valueFromSchema(fvl, pBTO->getSchema());
		
		    CegoBTreeManager btreeMng(this, pBTO);			
		    btreeMng.deleteBTree(btv, dp, getTID(oe.getTabSetId()));						
		    i++;		    
		}

		pBTO = btreeList.Next();
	    }	    
	}
	
	throw Exception(EXLOC, Chain("Cannot insert table data"), e);
    }
    
    // increase lob refs here

    pF = fvl.First();
    while (pF)
    {
	if ( pF->getValue().getType() == BLOB_TYPE  )
	{
	    PageIdType pageId;
	    memcpy(&pageId, pF->getValue().getValue(), sizeof(PageIdType));
	    
	    increaseBlobRef(oe.getTabSetId(), pageId);
	}
	else if ( pF->getValue().getType() == CLOB_TYPE  )
	{
	    PageIdType pageId;
	    memcpy(&pageId, pF->getValue().getValue(), sizeof(PageIdType));
	    
	    increaseClobRef(oe.getTabSetId(), pageId);
	}

	pF = fvl.Next();
    }

    if (oe.getType() == CegoObject::TABLE && doLogging == true)
    {

	ListT<CegoBlob> blobList;
	getBlobs(oe.getTabSetId(), fvl, blobList);

	ListT<CegoClob> clobList;
	getClobs(oe.getTabSetId(), fvl, clobList);

	if ( blobList.Size() > 0 || clobList.Size() > 0 )
	{

	    encLen = CegoQueryHelper::encodeFVL(tid, tastep, ts, fvl, blobList, clobList, _pEncBuf, _encBufLen);
	    
	    CegoBlob *pBlob = blobList.First();
	    while ( pBlob )
	    {
		pBlob->release();
		pBlob = blobList.Next();
	    }
	    CegoClob *pClob = clobList.First();
	    while ( pClob )
	    {
		pClob->release();
		pClob = clobList.Next();
	    }
	}

	lr.setObjectInfo(oe.getName(), CegoObject::TABLE);
	
	lr.setAction(CegoLogRecord::LOGREC_INSERT);
	lr.setLSN(_pDBMng->nextLSN(oe.getTabSetId()));
	lr.setData(_pEncBuf);
	lr.setDataLen(encLen);
	
	lr.setTID(getTID(oe.getTabSetId()));
	if ( getTID(oe.getTabSetId()) > 0 )
	    lr.setTAStep(_tastep[oe.getTabSetId()]);
	else
	    lr.setTAStep(0);

	_pDBMng->logIt(oe.getTabSetId(), lr, _pLockHandle, flushLog);
    }    
}

unsigned long long CegoTableManager::updateDataTable(unsigned tabSetId, const Chain& tableName,
						     const Chain& tableAlias,
						     CegoPredicate* pPred,
						     const ListT<CegoField>& updList,
						     ListT<CegoExpr*>& exprList,
						     bool returnOnFirst,
						     ListT<CegoField>& returnList,
						     CegoProcBlock* pBlock)
{	
    ListT<CegoTableObject> idxList;
    ListT<CegoBTreeObject> btreeList;
    ListT<CegoKeyObject> keyList;
    ListT<CegoCheckObject> checkList;
    ListT<CegoTriggerObject> triggerList;
    ListT<CegoAliasObject> aliasList;
    unsigned numInvalid;
    
    getObjectListByTable(tabSetId, tableName, idxList, btreeList, keyList, checkList, triggerList, aliasList, numInvalid);
    
    if ( numInvalid > 0 )
    {	    
	throw Exception(EXLOC, Chain("Invalid index detected, must be valid for update operations"));    
    }
    
    unsigned long long updCount = updateDataTable(tabSetId, tableName, tableAlias,
						  idxList, btreeList, keyList, checkList,
						  pPred, updList, exprList, returnOnFirst, returnList, pBlock);

    return updCount;
}

unsigned long long CegoTableManager::updateDataTable(unsigned tabSetId, const Chain& tableName, const Chain& tableAlias,
						     const ListT<CegoTableObject>& idxList, 
						     const ListT<CegoBTreeObject>& btreeList, 
						     const ListT<CegoKeyObject>& keyList, 
						     const ListT<CegoCheckObject>& checkList,
						     CegoPredicate* pPred,
						     const ListT<CegoField>& updList,
						     ListT<CegoExpr*>& exprList,
						     bool returnOnFirst,
						     ListT<CegoField>& returnList,
						     CegoProcBlock* pBlock)
{
    
    unsigned long long updCount = 0;

    unsigned long long tid = getTID(tabSetId);

    CegoLogRecord lr;
    lr.setObjectInfo(tableName, CegoObject::TABLE);    
    lr.setAction(CegoLogRecord::LOGREC_UPDATE);
    
    // increase tastep to filter out modifications for this step for any cursor
    if ( tid != 0 )
	_tastep[tabSetId]++;

    lr.setTID(tid);
    if ( tid > 0 )
	lr.setTAStep(_tastep[tabSetId]);
    else
	lr.setTAStep(0);

    CegoTableObject oe;    
    CegoBufferPage bp;
    getObjectWithFix(tabSetId, tableName, CegoObject::TABLE, oe, bp);

    // make log entry first 

    ListT<CegoBlob> blobList;    
    getBlobs(oe.getTabSetId(), exprList, pBlock, blobList);

    ListT<CegoClob> clobList;
    getClobs(oe.getTabSetId(), exprList, pBlock, clobList);

    char *pLogBuf = 0;
    unsigned logBuflen = 0;

    CegoQueryHelper::encodeUpdRec(tableAlias, pPred, updList, exprList, blobList, clobList, returnOnFirst, pBlock, pLogBuf, logBuflen);
    
    lr.setData(pLogBuf);
    lr.setDataLen(logBuflen);
    
    try
    {	
	CegoDataPointer sysEntry(bp.getPageId(), bp.getEntryPos());
	
	ListT<CegoField> fl = oe.getSchema();

	// init returnlist with empty schema
	returnList = fl;

	if ( tableName != tableAlias )
	{
	    // set up the defined alias for attribute evaluation
	    CegoField *pF =  fl.First();
	    while (pF)
	    {
		pF->setTableAlias(tableAlias);
		pF = fl.Next();
	    }
	}
	
	if (pPred == 0)
	{

#ifdef CGDEBUG
	    _pDBMng->log(_modId, Logger::DEBUG, Chain("Updating ") + oe.getTabName() + Chain(" with fulltablescan"));
#endif	    

	    CegoTableCursor* pTC = new CegoTableCursor(this, tabSetId, oe.getTabName(), true);
	    
	    try
	    {
		bool moreTuple;
		
		CegoDataPointer dp;

		checkTypes(fl, updList);

		moreTuple = pTC->getFirst(fl, dp);

		while ( moreTuple
			&& _isAborted == false
			&& ( returnOnFirst == false || ( returnOnFirst == true && updCount == 0)) )
		{		    
		    Chain virginIndex;		   
		    if ( updateTuple(oe, tableAlias, sysEntry, dp, fl, updList, exprList, returnList, idxList, btreeList, keyList, checkList, virginIndex, _doAppend, pBlock) )
			updCount++;
		    
		    moreTuple = pTC->getNext(fl, dp);		    
		}
	    }
	    catch ( Exception e )
	    {
		delete pTC;
		throw Exception(EXLOC, Chain("Cannot update table ") + tableName, e);
	    }

	    CegoQueryHelper::localizeFL(returnList);
	    
	    delete pTC;
	    
	    if ( _isAborted )
	    {	    
		throw Exception(EXLOC, Chain("Update aborted by user"));
	    } 		
	} 
	else
	{	    
	    ListT<CegoField>* xfl[3];
	    xfl[0] = &fl;
	    if ( pBlock )
		xfl[1] = pBlock->getTriggerValueList();
	    else
		xfl[1] = 0;
	    xfl[2] = 0; // terminate in any case
	    
	    ListT<CegoSelect*> queryList;
	    pPred->getSelectQueryList(queryList);
	    CegoSelect **pSelect = queryList.First();
	    while ( pSelect )
	    {
		(*pSelect)->setParentJoinBuf(xfl);
		pSelect = queryList.Next();
	    }
	    pPred->analyzeSelect();
	    
	    // we have to resolve external references in a second step, since they are handled with lower priority
	    pSelect = queryList.First();
	    while ( pSelect )
	    {
		// before evaluating external table references, we have to prepare to resolve native query attributes first
		(*pSelect)->prepare();
		
		(*pSelect)->evalExtTableReferences(&oe, fl);
		pSelect = queryList.Next();
	    }
	   	    
	    CegoAttrCond ac;	    
	    CegoQueryHelper::AttrCondMatch m = CegoQueryHelper::checkAttrCond(ac, pPred, fl, &fl,1, pBlock);

	    if  ( m == CegoQueryHelper::COMPLETE )
	    {
		bool isAffected = false;

		CegoAttrComp *pAC = 0;
		pAC = ac.getAttrCompSet().First();
		
		while ( pAC )
		{		    
		    CegoField *pF = updList.First();
		    while ( pF && isAffected == false )
		    {
			if ( pF->getAttrName() == pAC->getAttrName() )
			{
			    isAffected = true;
			}
			else
			{
			    pF = updList.Next();
			}
		    }

		    pAC = ac.getAttrCompSet().Next();

		}
		if ( isAffected == true )
		    m = CegoQueryHelper::INAPP;
	    }

	    if ( m == CegoQueryHelper::INAPP )
	    {
#ifdef CGDEBUG	
		_pDBMng->log(_modId, Logger::DEBUG, Chain("Updating ") + oe.getTabName() + Chain(" with fulltablescan"));	    
#endif		
		CegoTableCursor* pTC = new CegoTableCursor(this, tabSetId, oe.getTabName(), true);

		try 
		{
		    bool moreTuple;
		    
		    CegoDataPointer dp;

		    checkTypes(fl, updList);
				
		    moreTuple = pTC->getFirst(fl, dp);
		
		    while ( moreTuple
			    && _isAborted == false
			    && ( returnOnFirst == false || ( returnOnFirst == true && updCount == 0 ) ) )
		    {
			pPred->clearAttrCache();

			if ( pPred->eval(0, 0, xfl, 0, pBlock))
			{			    
			    Chain virginIndex;
			    
			    if ( updateTuple(oe, tableAlias, sysEntry, dp, fl, updList, exprList, returnList, idxList, btreeList, keyList, checkList, virginIndex, _doAppend, pBlock) )
				updCount++;
			    
			    moreTuple = pTC->getNext(fl, dp);
			}
			else
			{
			    moreTuple = pTC->getNext(fl, dp);   
			}	 
		    }
		}
		catch ( Exception e )
		{
		    // now we can release the index root page
		    delete pTC;
		    throw Exception(EXLOC, Chain("Cannot update data table"), e);
		}

		CegoQueryHelper::localizeFL(returnList);
		
		delete pTC;
		
		if ( _isAborted )
		{	    
		    throw Exception(EXLOC, Chain("Update aborted by user"));
		} 		
	    }
	    else
	    {		
#ifdef CGDEBUG	
		_pDBMng->log(_modId, Logger::DEBUG, Chain("Updating ") + oe.getTabName() + Chain(" using AttrCond ") + ac.toChain());		
#endif
		CegoTableCursor *pTC = new CegoTableCursor(this, tabSetId, oe.getTabName(), true);
		Chain virginIndex;
		
		try 
		{
		    checkTypes(fl, updList);
		    
		    CegoAttrCond::IndexMatch indexMatch = pTC->setup(ac);		  
		    CegoObject::ObjectType virginType = CegoObject::UNDEFINED;

		    if ( indexMatch == CegoAttrCond::FULL || indexMatch == CegoAttrCond::PART )
		    {
			virginIndex = pTC->getIndexName();
			virginType = pTC->getIndexType();
		    }

#ifdef CGDEBUG	
		    _pDBMng->log(_modId, Logger::DEBUG, Chain("Virgin index is ") + virginIndex);		    
#endif
		    bool moreTuple;
		    CegoDataPointer dp;
		    
		    moreTuple = pTC->getFirst(fl, dp);
				    
		    while ( moreTuple
			    && _isAborted == false
			    && ( returnOnFirst == false || ( returnOnFirst == true && updCount == 0 ) ) )
		    {
#ifdef CGDEBUG	
			_pDBMng->log(_modId, Logger::DEBUG, Chain("Checking pred for update ..."));
#endif
			pPred->clearAttrCache();
			if ( pPred->eval(0, 0, xfl, 0, pBlock))
			{			    
#ifdef CGDEBUG	
			    _pDBMng->log(_modId, Logger::DEBUG, Chain("Updating tuple..."));
#endif

			    if ( updateTuple(oe, tableAlias, sysEntry, dp, fl, updList, exprList, returnList, idxList, btreeList, keyList, checkList, virginIndex, _doAppend, pBlock) )
				updCount++;				

			    moreTuple = pTC->getNext(fl, dp);
			}    
			else
			{
			    moreTuple = pTC->getNext(fl, dp);   
			}
		    }
#ifdef CGDEBUG	
		    _pDBMng->log(_modId, Logger::DEBUG, Chain("Commiting update "));		    
#endif	    
		    if ( virginIndex != Chain() )
			_pTM->commitUpdate(tabSetId, virginIndex, virginType, getTID(tabSetId), _doAppend);
		}
		catch ( Exception e )
		{
		    if ( virginIndex != Chain() )
		    {
			_pTM->abortUpdate(tabSetId, getTID(tabSetId));
		    }
		    
		    delete pTC;
		    throw Exception(EXLOC, Chain("Cannot update data table"), e);
		}

		CegoQueryHelper::localizeFL(returnList);
		
		delete pTC;
		
		if ( _isAborted )
		{	    
		    throw Exception(EXLOC, Chain("Update aborted by user"));
		}		    
	    }

	    // cleanup 
	    pSelect = queryList.First();
	    while ( pSelect )
	    {
		(*pSelect)->setParentJoinBuf();
		pSelect = queryList.Next();
	    }

	}
    }
    catch ( Exception e )
    {	
	if ( logBuflen > 0 )
	    free ( pLogBuf );

	// now we can release the index root page
	_pDBMng->bufferUnfix(bp, true, _pLockHandle);
	throw Exception(EXLOC, Chain("Cannot update data table"), e);
    }

    _pDBMng->bufferUnfix(bp, true, _pLockHandle); 
 
#ifdef CGDEBUG	
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Update finished, updCount = ") + Chain(updCount));
#endif


    // log update record
    lr.setLSN(_pDBMng->nextLSN(tabSetId));
    _pDBMng->logIt(oe.getTabSetId(), lr, _pLockHandle);
    if ( logBuflen > 0 )
	free ( pLogBuf );

    return updCount;
}

bool CegoTableManager::updateTuple(CegoTableObject& oe, const Chain& tableAlias,
				   const CegoDataPointer& sysEntry, const CegoDataPointer& dp, 
				   ListT<CegoField>& fl, 
				   const ListT<CegoField>& nfvl,
				   ListT<CegoExpr*>& exprList,
				   ListT<CegoField>& updSchema,
				   const ListT<CegoTableObject>& idxList,
				   const ListT<CegoBTreeObject>& btreeList,
				   const ListT<CegoKeyObject>& keyList, 
				   const ListT<CegoCheckObject>& checkList, 
				   const Chain& virginIndex,
				   bool doAppend,
				   CegoProcBlock* pBlock)
{
#ifdef CGDEBUG	
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Updating tuple for ") + oe.getTabName());
#endif
    
    CegoField* pFV = nfvl.First();
    CegoExpr** pExpr = exprList.First();
    
    while ( pFV && pExpr)
    {
	ListT<CegoField>* fla[3];
	fla[0] = &fl;
	if ( pBlock )
	    fla[1] = pBlock->getTriggerValueList();
	else
	    fla[1] = 0;
	fla[2] = 0;// terminate in any case

	
	// (*pExpr)->setFieldListArray(fla);
	// set block must be set after setFieldListArray, since in CegoFactor, sub queries are prepared
	// for preparation, field list array is needed
	
	// (*pExpr)->setBlock(pBlock);

	ListT<CegoSelect*> queryList;
        (*pExpr)->getSelectQueryList(queryList);
        CegoSelect **pSelect = queryList.First();
	
        while ( pSelect )
        {
	    CegoTableObject refTO = oe;
	    refTO.setTabAlias(tableAlias);
            (*pSelect)->setParentJoinBuf(fla);

	    (*pSelect)->prepare();

	    // external table refrences must be evaluated here to
	    // ensure correct update operations with nested select with enabled querycache

            // int refCount =
	    (*pSelect)->evalExtTableReferences(&refTO, fl);

            pSelect = queryList.Next();
        }
	
	(*pExpr)->clearAttrCache();

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

	CegoQueryHelper::prepareFieldValue(pFV, fv, this, oe.getTabSetId());

	pFV->setValue(fv);

	// cleanup 
	pSelect = queryList.First();
        while ( pSelect )
        {
            (*pSelect)->setParentJoinBuf();
            pSelect = queryList.Next();
        }
	
	pFV = nfvl.Next();
	pExpr = exprList.Next();
    }

    if ( pFV || pExpr )
    {
	throw Exception(EXLOC, Chain("Mismatched argument count for value list"));
    }
        
    // init updschema with original fl
    updSchema = fl;
    
    // setup updated values in updschema
    CegoField* pUF = nfvl.First();
    while ( pUF )
    {
	CegoField *pF = updSchema.Find(*pUF);
	if ( pF )
	{
	    pF->setValue(pUF->getValue());
	}
	pUF = nfvl.Next();
    }

    bool updateDone=false;
    unsigned long long recLock = 0;
    
    try
    {	
	recLock = _pLockHandle->lockRecord(dp, CegoLockHandler::WRITE);

	checkIntegrity( oe.getTabSetId(), oe.getTabName(), idxList, btreeList, keyList, checkList, dp, fl, updSchema);
	
	/* the update operation is devided into a delete and an insert operation */
	/* We dont have to write dedicated redo log entries, since a log entry for update is already done => logging = false */

	if ( deleteDataTableEntry(oe.getTabSetId(), oe.getTabName(), oe.getType(), dp, fl, idxList, btreeList, keyList, false) )
	{
	    CegoDataPointer ndp;

	    bool increaseStep = false;
	    bool flushLog = true;
	    insertDataTable(oe, updSchema, idxList, btreeList, keyList, checkList, sysEntry, virginIndex, ndp, false, doAppend, increaseStep, flushLog);
	    
	    if ( virginIndex != Chain() )
	    {
		_pTM->recordUpdate(oe.getTabSetId(), getTID(oe.getTabSetId()), ndp);
	    }
	    
	    updateDone =  true;
	}
	else
	{
	    // if delete failed, we have to cleanup lob data
	    CegoField* pF = updSchema.First();	    
	    while ( pF)
	    {
		if ( pF->getValue().getType() == BLOB_TYPE && pF->getValue().getValue() != 0 )
		{
		    PageIdType pageId;
		    memcpy(&pageId, pF->getValue().getValue(), sizeof(PageIdType));
		    
		    decreaseBlobRef(oe.getTabSetId(), pageId);
		}
		
		if ( pF->getValue().getType() == CLOB_TYPE && pF->getValue().getValue() != 0 )
		{
		    PageIdType pageId;
		    memcpy(&pageId, pF->getValue().getValue(), sizeof(PageIdType));
		    
		    decreaseClobRef(oe.getTabSetId(), pageId);
		}
		
		pF = updSchema.Next();
	    }
	}
	   
	_pLockHandle->unlockRecord(recLock);
	return updateDone;
    }	    
    catch ( Exception e )
    {	    
	if ( recLock )
	    _pLockHandle->unlockRecord(recLock);
	throw Exception(EXLOC, Chain("Cannot update tuple"), e);
    }
}

void CegoTableManager::getKeyAndIdxRef(unsigned tabSetId, const Chain& tableName, const Chain& attrName, 
				       ListT<CegoKeyObject>& refKeyList,
				       ListT<CegoTableObject>& refIdxList,
				       ListT<CegoBTreeObject>& refBTreeList)
{    
    ListT<CegoTableObject> idxList;
    ListT<CegoBTreeObject> btreeList;
    ListT<CegoKeyObject> keyList;
    ListT<CegoCheckObject> checkList;
    ListT<CegoTriggerObject> triggerList;
    ListT<CegoAliasObject> aliasList;
    unsigned numInvalid;

    getObjectListByTable(tabSetId, tableName, idxList, btreeList, keyList, checkList, triggerList, aliasList, numInvalid);
        
    if ( ! keyList.isEmpty() )
    {
	CegoKeyObject* pKey = keyList.First();
	while ( pKey )
	{
	    if ( (Chain)pKey->getTabName() == (Chain)tableName )
	    {		
		CegoField *pF = pKey->getKeySchema().First();
		while ( pF )
		{
		    if ( pF->getAttrName() == attrName )
		    {
			refKeyList.Insert(*pKey);
		    }
		    pF = pKey->getKeySchema().Next();
		}
	    }
	    else if ( (Chain)pKey->getRefTable() == (Chain)tableName )
	    {
		CegoField *pF = pKey->getRefSchema().First();
		while ( pF )
		{
		    if ( pF->getAttrName() == attrName )
		    {
			refKeyList.Insert(*pKey);
		    }
		    pF = pKey->getRefSchema().Next();
		}	      
	    }
	    pKey = keyList.Next();
	}
    }
    if ( ! idxList.isEmpty() )
    {
	CegoTableObject* pIdx = idxList.First();
	while ( pIdx )
	{	    
	    CegoField *pF = pIdx->getSchema().First();
	    while ( pF )
	    {	
		if ( pF->getAttrName() == attrName )
		{
		    refIdxList.Insert(*pIdx);
		    // return true;
		}
		pF = pIdx->getSchema().Next();
	    }
	    pIdx = idxList.Next();
	}	
    }

    if ( ! btreeList.isEmpty() )
    {
	CegoBTreeObject* pBTree = btreeList.First();
	while ( pBTree )
	{	    
	    CegoField *pF = pBTree->getSchema().First();
	    while ( pF )
	    {
		if ( pF->getAttrName() == attrName )
		{
		    refBTreeList.Insert(*pBTree);
		    // return true;
		}
		pF = pBTree->getSchema().Next();
	    }
	    pBTree = btreeList.Next();
	}	
    }

    return;
}

bool CegoTableManager::keyReferenceExists(unsigned tabSetId, const Chain& tableName, const ListT<CegoField>& fl, const ListT<CegoKeyObject>& keyList)
{
    if ( ! keyList.isEmpty() )
    {
        CegoKeyObject* pKey = keyList.First();
        while ( pKey )
        {
            if ( (Chain)pKey->getRefTable() == (Chain)tableName )
            {		
                CegoTableCursor tc(this, tabSetId, pKey->getTabName());
		
                CegoField *pKF = pKey->getKeySchema().First();
                CegoField *pRF = pKey->getRefSchema().First();
		
                CegoAttrCond ac;
 
                while ( pKF && pRF )
                {
                    CegoField *pF = fl.Find(*pRF);
                    ac.add(CegoAttrComp(pKF->getTableAlias(), pKF->getAttrName(), EQUAL, pF->getValue()));
		    
                    pKF = pKey->getKeySchema().Next();
                    pRF = pKey->getRefSchema().Next();
                }
		                				            
		CegoTableObject oe;
		getObject(tabSetId, pKey->getTabName(), CegoObject::TABLE, oe);

		ListT<CegoField> kfl = oe.getSchema();

                pKF = kfl.First();
                while ( pKF )
                {
                    pKF->setTableName(pKey->getTabName());
                    pKF->setTableAlias(pKey->getTabName());
		    
                    CegoField *pF = fl.Find(CegoField(pKF->getTableAlias(), pKF->getAttrName()));
                    if ( pF )
                    {
			pKF->setId(pF->getId());
                    }
                    pKF = kfl.Next();
                }
                CegoDataPointer dp;

		CegoAttrCond::IndexMatch indexMatch = tc.setup(ac);
                bool moreTuple = tc.getFirst(kfl, dp);
		
                if ( indexMatch == CegoAttrCond::FULL )
                {		    
		    if ( moreTuple )
		    {
			// treat self refering tables
			if ( pKey->getRefTable() == pKey->getTabName() )
			{
			    pRF = pKey->getRefSchema().First();
			    while ( pRF )
			    {
				// we just search for attrname, since must be unique and tablename could be setup with alias
				CegoField *pF = fl.Find(CegoField(Chain(), pRF->getAttrName()));
				if ( pF )
				{
				    CegoField *pKFV = kfl.Find(*pRF);
				    if ( pKFV )
				    {					
					if ( ! ( (CegoFieldValue)pF->getValue() == (CegoFieldValue)pKFV->getValue()) )
					{
					    // cursor tuple is not the to-deleted tuple, so we really found a key reference
					    return true;
					}
				    }
				    else
				    {
					Chain msg = Chain("Unknown key attribute <" ) + pRF->getAttrName() + Chain(">");
					throw Exception(EXLOC, msg);
				    }
				}
				pRF = pKey->getRefSchema().Next();
			    }
			}
			else
			{
			    return true;
			}			
		    }
                }
                else
                {		    
		    while ( moreTuple )
		    {
			bool isMatch = true;
			pKF = pKey->getKeySchema().First();
			pRF = pKey->getRefSchema().First();
			while ( pKF && pRF && isMatch)
			{
			    // we just search for attrname, since must be unique and tablename could be setup with alias
			    CegoField *pF = fl.Find(CegoField(Chain(), pRF->getAttrName()));
			    if ( pF )
			    {
				CegoField *pKFV = kfl.Find(*pKF);
				if ( ! ( (CegoFieldValue)pF->getValue() == (CegoFieldValue)pKFV->getValue()) )
				{
				    isMatch=false;
				}
			    }
			    else
			    {
				Chain msg = Chain("Unknown key attribute <" ) + pKF->getAttrName() + Chain(">");
				throw Exception(EXLOC, msg);
			    }
			    pRF = pKey->getRefSchema().Next();
			    pKF = pKey->getKeySchema().Next();
			}
			if ( isMatch )
			{
			    // for self refering keys, we still have to check primary key,
			    // if cursor tuple != delete tuple
			    
			    if ( pKey->getRefTable() == pKey->getTabName() )
			    {
				pRF = pKey->getRefSchema().First();
				while ( pRF )
				{
				    // we just search for attrname, since must be unique and tablename could be setup with alias
				    CegoField *pF = fl.Find(CegoField(Chain(), pRF->getAttrName()));
				    if ( pF )
				    {
					CegoField *pKFV = kfl.Find(*pRF);
					if ( pKFV )
					{
					    if ( ! ( (CegoFieldValue)pF->getValue() == (CegoFieldValue)pKFV->getValue()) )
					    {
						// cursor tuple is not the to-deleted tuple,
						// so we really found a key reference
						return true;
					    }
					}
					else
					{
					    Chain msg = Chain("Unknown key attribute <" ) + pRF->getAttrName() + Chain(">");
					    throw Exception(EXLOC, msg);
					}
				    }
				    pRF = pKey->getRefSchema().Next();
				}
			    }
			    else
			    {
				return true;
			    }
			}			    
			moreTuple = tc.getNext(kfl, dp);			
                    }
                }
            }
            pKey = keyList.Next();
        }
    }
    return false;
}

void CegoTableManager::checkIntegrity(unsigned tabSetId,
				      const Chain& tableName,
				      const ListT<CegoTableObject>& idxList,
				      const ListT<CegoBTreeObject>& btreeList,
				      const ListT<CegoKeyObject>& keyList,
				      const ListT<CegoCheckObject>& checkList,
				      const CegoDataPointer& dp, const ListT<CegoField>& fvl, const ListT<CegoField>& nfvl)
{
    checkIndexIntegrity(idxList, tabSetId, dp, fvl, nfvl);
    checkBTreeIntegrity(btreeList, tabSetId, dp, fvl, nfvl);
    checkKeyIntegrity(keyList, tabSetId, tableName, fvl, nfvl);
    checkCheckIntegrity(checkList, nfvl);
}

void CegoTableManager::checkKeyIntegrity(const ListT<CegoKeyObject>& keyList, unsigned tabSetId, const Chain& tableName, const ListT<CegoField>& fvl, const ListT<CegoField>& nfvl)
{
    CegoKeyObject* pKey = keyList.First();
    while ( pKey )
    {
        if ( (Chain)pKey->getRefTable() == (Chain)tableName )
        {
            CegoTableCursor tc(this, tabSetId, pKey->getTabName());
            CegoField *pRF, *pKF;
	    
            // get reference key value from old tuple value
            ListT<CegoField> rfl = pKey->getRefSchema();
            pRF = rfl.First();
            while ( pRF )
            {
                CegoField *pF = fvl.Find(*pRF);
                if ( pF )
                {
                    pRF->setValue(pF->getValue());
                }
		else
		{
		    Chain msg = Chain("Unknown reference attribute <" ) + pRF->getAttrName() + Chain(">");
		    throw Exception(EXLOC, msg);	    
		}
 
                pRF = rfl.Next();
            }
 
            CegoAttrCond ac;
            pKF = pKey->getKeySchema().First();
            pRF = rfl.First();
            while ( pKF && pRF )
            {
                ac.add(CegoAttrComp(pKey->getTabName(), pKF->getAttrName(), EQUAL, pRF->getValue()));
		
                pKF = pKey->getKeySchema().Next();
                pRF = rfl.Next();
            }
 
            CegoAttrCond::IndexMatch indexMatch = tc.setup(ac);
 
            CegoTableObject oe;
            getObject(tabSetId, pKey->getTabName(), CegoObject::TABLE, oe);
           
            ListT<CegoField> kfl = pKey->getKeySchema();
            pKF = kfl.First();
            while ( pKF )
            {
                pKF->setTableName(pKey->getTabName());
                pKF->setTableAlias(pKey->getTabName());
 
                CegoField *pF = oe.getSchema().Find(CegoField(pKey->getTabName(), pKF->getAttrName()));
                if ( pF )
                {
                    pKF->setId(pF->getId());
                    pKF = kfl.Next();
                }
            }
 
            CegoDataPointer dp;
            bool moreTuple = tc.getFirst(kfl, dp);
 
            if ( indexMatch == CegoAttrCond::FULL )
            {
                if ( moreTuple )
                {
                    bool keyMatch=true;
                    pKF = kfl.First();
                    pRF = rfl.First();
                    while ( pKF && pRF && keyMatch)
                    {
			// we must search for undefined tablename, since for update opertions, also an alias could be setup
                        CegoField *pNF = nfvl.Find(CegoField(Chain(), pRF->getAttrName()));
                        if ( pNF )
                        {
                            if ( ! ( (CegoFieldValue)pNF->getValue() == (CegoFieldValue)pKF->getValue()) )
                            {
                                keyMatch=false;
                            }
                        }
                        pKF = kfl.Next();
                    }
                    if ( keyMatch == false )
		    {
			Chain msg = Chain("Foreign key " ) + pKey->getName() + Chain(" violated");
			throw Exception(EXLOC, msg);	    
		    }
                    return; //  true;
                }
                return; //  true;
            }
            else
            {
                while ( moreTuple )
                {
                    bool isMatch = true;
                    pKF = kfl.First();
                    pRF = rfl.First();
                    while ( pKF && pRF && isMatch)
                    {
			// we must search for undefined tablename, since for update opertions, also an alias could be setup
                        CegoField *pF = fvl.Find(CegoField(Chain(), pRF->getAttrName()));
                        if ( pF )
                        {
                            if ( ! ( (CegoFieldValue)pF->getValue() == (CegoFieldValue)pKF->getValue()) )
                            {                       
                                isMatch=false;
                            }
                        }
                        else
                        {
			    Chain msg = Chain("Unknown key attribute <" ) + pKF->getAttrName() + Chain(">");
			    throw Exception(EXLOC, msg);
                        }
                        pRF = rfl.Next();
                        pKF = kfl.Next();
                    }
                    if ( isMatch )
                    {
                        bool keyMatch=true;
                        pKF = kfl.First();
                        pRF = rfl.First();
                        while ( pKF && pRF && keyMatch)
                        {
			    // we must search for undefined tablename, since for update opertions, also an alias could be setup
                            CegoField *pNF = nfvl.Find(CegoField(Chain(), pRF->getAttrName()));
                            if ( pNF )
                            {
                                if ( ! ( (CegoFieldValue)pNF->getValue() == (CegoFieldValue)pKF->getValue()) )
                                {                              
                                    keyMatch=false;
                                }
                            }
			    else
			    {
				Chain msg = Chain("Unknown reference attribute <" ) + pRF->getAttrName() + Chain(">");
				throw Exception(EXLOC, msg);				
			    }
                            pRF = rfl.Next();
                            pKF = kfl.Next();
                        }
                        if ( keyMatch == false )
			{
			    Chain msg = Chain("Foreign key " ) + pKey->getName() + Chain(" violated");
			    throw Exception(EXLOC, msg);
			    //    return false;
			}
                    }
                    moreTuple = tc.getNext(kfl, dp);
                }
                return; // true;
            }
        }
       pKey = keyList.Next();
    }
    return; // true;
}

void CegoTableManager::checkIndexIntegrity(const ListT<CegoTableObject>& idxList, unsigned tabSetId, const CegoDataPointer& dp, const ListT<CegoField>& fvl, const ListT<CegoField>& nfvl)
{
    CegoTableObject* pOE = idxList.First();
    
    while (pOE)
    {
	if ( pOE->getType() == CegoObject::UAVLTREE 
	     || pOE->getType() == CegoObject::PAVLTREE )
	{	    
	    CegoFieldValue fv = getIndexSearchValue(pOE->getSchema(), nfvl);
	    
	    CegoField *pF = pOE->getSchema().First();
	    
	    CegoAttrCond ac;
	    ac.add(CegoAttrComp( pF->getTableAlias(), pF->getAttrName(), EQUAL, fv));
	    
	    CegoAVLIndexCursor ic(this, tabSetId, pOE->getName(), pOE->getType(), &ac, false, true);
	    
	    CegoDataPointer ndp;
	    ListT<CegoField> oe = pOE->getSchema();
	    
	    bool attrMatch = ic.getFirst(oe, ndp);
	    
	    while ( attrMatch )
	    {	
		CegoField *pIF = oe.First();
		while ( pIF && attrMatch )
		{
		    CegoField *pNF = nfvl.Find(*pIF);
		    
		    if ( pNF )
		    {
			if ( pNF->getValue() != pIF->getValue() )
			    attrMatch = false;
			else
			    pIF = oe.Next();
		    }
		    else
		    {
			pIF = oe.Next();
		    }			
		}
		
		if ( ndp != dp && attrMatch )
		{
		    ic.abort();
		    
		    Chain msg = Chain("Duplicate entry for index " ) + pOE->getName();
		    throw Exception(EXLOC, msg);
		}
		
		attrMatch = ic.getNext(oe, ndp);
	    }
	}
	pOE = idxList.Next();
    }
    return;
}

void CegoTableManager::checkBTreeIntegrity(const ListT<CegoBTreeObject>& btreeList, unsigned tabSetId, const CegoDataPointer& dp, const ListT<CegoField>& fvl, const ListT<CegoField>& nfvl)
{
    CegoBTreeObject* pOE = btreeList.First();
    
    while (pOE)
    {
	if ( pOE->getType() == CegoObject::UBTREE 
	     || pOE->getType() == CegoObject::PBTREE )
	{	    
	    CegoFieldValue fv = getIndexSearchValue(pOE->getSchema(), nfvl);
	    
	    CegoField *pF = pOE->getSchema().First();
	    
	    CegoAttrCond ac;
	    ac.add(CegoAttrComp( pF->getTableAlias(), pF->getAttrName(), EQUAL, fv));
	    
	    CegoBTreeCursor btc(this, tabSetId, pOE->getName(), pOE->getType(), &ac, false, true);
	    
	    CegoDataPointer ndp;

	    ListT<CegoField> oe = pOE->getSchema();
	    bool attrMatch = btc.getFirst(oe, ndp);

	    if ( attrMatch && __allowDuplicateNull && pOE->getType() == CegoObject::UBTREE )
	    {
		bool isNullValue=true;
		CegoField *pIF = oe.First();
		while ( pIF && isNullValue )
		{
		    isNullValue = pIF->getValue().isNull();
		    pIF = oe.Next();
		}
		
		if ( isNullValue )
		    attrMatch=false;
	    }
	    
	    while ( attrMatch )
	    {	
		CegoField *pIF = oe.First();
		while ( pIF && attrMatch )
		{
		    CegoField *pNF = nfvl.Find(*pIF);
		    
		    if ( pNF )
		    {
			if ( pNF->getValue() != pIF->getValue() )
			    attrMatch = false;
			else
			    pIF = oe.Next();
		    }
		    else
		    {
			pIF = oe.Next();
		    }			
		}
		
		if ( ndp != dp && attrMatch )
		{
		    // we still have to check the tuple state, it might be that the found entry
		    // was made by another transaction and is still not commited
		    
		    unsigned long long tid;
		    unsigned long long tastep;
		    CegoTupleState ts;
		    
		    getTupleInfo(tabSetId, ndp, tid, tastep, ts);			

		    if ( ts == COMMITTED )
		    {	
			//  just if the tuple state is commited, 
			//  we have detected a duplicate			  
			
			btc.abort();

			Chain keyValue;
			CegoField *pIF = oe.First();
			while ( pIF  )
			{
			    keyValue += pIF->getValue().valAsChain();
			    pIF = oe.Next();
			    if ( pIF )
				keyValue += Chain(",");			    
			}					
			
			Chain msg = Chain("Dupliate key ") + keyValue + Chain(" on unique btree ") + pOE->getName();
			throw Exception(EXLOC, msg);
		    }
		}		
		attrMatch = btc.getNext(oe, ndp);
	    }	    
	}
	pOE = btreeList.Next();
    }
    return; //  true;
}

void CegoTableManager::checkCheckIntegrity(const ListT<CegoCheckObject>& checkList, const ListT<CegoField>& nfvl)
{
    if ( ! checkList.isEmpty() )
    {
	// we need to make a copy, since nvfl ist const    
	ListT<CegoField> fvl = nfvl;
	
	CegoCheckObject* pCheck = checkList.First();
	while ( pCheck )
	{	
	    pCheck->getPredDesc()->clearAttrCache();
	    
	    ListT<CegoField>* xfl[2];
	    xfl[0] = &fvl;
	    xfl[1] = 0;	     
	    
	    if ( pCheck->getPredDesc()->eval(0, 0, xfl, 0, 0) == false )
	    {
		Chain msg = Chain("Check constraint ") + pCheck->getName() + Chain(" violated");		
		throw Exception(EXLOC, msg);
	    }
	    
	    pCheck = checkList.Next();
	}
    }
    return; // true;
}

bool CegoTableManager::checkNullValue(unsigned tabSetId, const Chain& tableName, const CegoField& f)
{
    CegoTableCursor *pTC = new CegoTableCursor(this, tabSetId, tableName);
    CegoAttrCond attrCond;
    CegoFieldValue nullValue;

    bool hasNullValue = false;

    attrCond.add(CegoAttrComp(f.getTableAlias(), f.getAttrName(), EQUAL, nullValue)); 
    CegoAttrCond::IndexMatch m = pTC->setup(attrCond);
    CegoDataPointer dp;
    ListT<CegoField> fl;
    CegoField *pF;

    if ( m == CegoAttrCond::INAPP )
    {
	fl.Insert(f);
	if ( pTC->getFirst(fl, dp) )
	{
	    pF = fl.First();
	    if ( pF )
	    {
		if ( pF->getValue() == nullValue )
		{
		    hasNullValue = true;
		}
		else
		{
		    while ( pTC->getNext(fl, dp) && hasNullValue == false)
		    {
			pF = fl.First();
			if ( pF )
			{
			    if ( pF->getValue() == nullValue )
			    {
				hasNullValue = true;
			    }	 
			}   
		    }
		}
	    }
	}
    }
    else
    {
	fl.Insert(f);
	if ( pTC->getFirst(fl, dp) )
	{
	    hasNullValue = true;
	}
    }
    pTC->abort();
    delete pTC;

    return hasNullValue;
}

void CegoTableManager::checkTypes(const ListT<CegoField>& fl, const ListT<CegoField>& nfl)
{    
    CegoField *pF = fl.First();
    while ( pF )
    {
	CegoField *pD = nfl.Find(*pF);
	if ( pD )
	{
	    if ( pD->getType() != pF->getType() )
	    {
		throw Exception(EXLOC, Chain("Mismatched data type <")
				+ CEGO_TYPE_MAP[(unsigned)(pD->getType())] 
				+ Chain("> for attribute ") + pF->getAttrName() 
				+ Chain(", expected type <")
				+ CEGO_TYPE_MAP[(unsigned)(pF->getType())]
				+ Chain(">"));
	    }
	}
	pF = fl.Next();
    }
}

const CegoFieldValue& CegoTableManager::getIndexSearchValue(const ListT<CegoField>& idxSchema, const ListT<CegoField>& nfvl)
{   
    CegoField *pSF = idxSchema.First();

    CegoField *pVF = nfvl.First();
    while ( pVF )
    {
	if ( (Chain)pSF->getAttrName() == (Chain)pVF->getAttrName() ) 
	    return pVF->getValue();
	pVF = nfvl.Next();
    }
    
    throw Exception(EXLOC, Chain("No index value found"));
}

unsigned long long CegoTableManager::deleteDataTable(CegoTableObject& oe, CegoPredicate* pPred, CegoProcBlock* pBlock, bool isSynced)
{
    ListT<CegoTableObject> idxList;
    ListT<CegoBTreeObject> btreeList;
    ListT<CegoKeyObject> keyList;
    ListT<CegoCheckObject> checkList;
    ListT<CegoTriggerObject> triggerList;
    ListT<CegoAliasObject> aliasList;
    unsigned numInvalid;
    
    getObjectListByTable(oe.getTabSetId(), oe.getTabName(), idxList, btreeList, keyList, checkList, triggerList, aliasList, numInvalid);
    
    if ( numInvalid > 0 )
    {
	throw Exception(EXLOC, Chain("Invalid index detected, must be valid for delete opertions"));
    }
        
    return deleteDataTable(oe, idxList, btreeList, keyList, pPred, pBlock, isSynced);   
}

unsigned long long CegoTableManager::deleteDataTable(CegoTableObject& oe,
						     const ListT<CegoTableObject>& idxList,
						     const ListT<CegoBTreeObject>& btreeList,
						     const ListT<CegoKeyObject>& keyList,
						     CegoPredicate* pPred, CegoProcBlock* pBlock, bool isSynced)
{
    unsigned long tid = getTID(oe.getTabSetId());

    // prepare log entry first
    CegoLogRecord lr;
    lr.setObjectInfo(oe.getName(), oe.getType());
    lr.setAction(CegoLogRecord::LOGREC_DELETE);
    lr.setTID(tid);

    if ( tid != 0 ) 
	_tastep[oe.getTabSetId()]++;

    if ( tid > 0 )
	lr.setTAStep(_tastep[oe.getTabSetId()]);
    else
	lr.setTAStep(0);

    unsigned long long delCount = 0;
    
    if (pPred == 0)
    {	
	CegoTableCursor* pTC = new CegoTableCursor(this, oe.getTabSetId(), oe.getTabName(), true);
	
	try
	{
	    bool moreTuple;
	    
	    CegoDataPointer dp;
	    ListT<CegoField> fl = oe.getSchema();
	    
	    moreTuple = pTC->getFirst(fl, dp);
	    
	    while (moreTuple && _isAborted == false )
	    {	    
		ListT<CegoField> nfl = oe.getSchema();	    
		CegoDataPointer ndp;
		moreTuple = pTC->getNext(nfl, ndp);

		deleteDataTableEntrySynced(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE, dp, fl, idxList, btreeList, keyList, true, false, isSynced);

		delCount++;
		
		if ( moreTuple )
		{
		    dp = ndp;
		    fl = nfl;
		}	    
	    }
	    
	    delete pTC;
	}
	catch ( Exception e)
	{
	    delete pTC;
	    throw Exception(EXLOC, Chain("Cannot delete data table"), e); 
	}
    } 
    else
    {
	if ( oe.getTabName() != oe.getTabAlias() )
	{
	    // set up the defined alias for attribute evaluation
	    CegoField *pF = oe.getSchema().First();
	    while (pF)
	    {
		pF->setTableAlias(oe.getTabAlias());		
		pF = oe.getSchema().Next();
	    }
	}

	ListT<CegoField> fl = oe.getSchema();

	// we need to create an additional reference to use the setFieldListArray method
	ListT<CegoField>* xfl[3];
	xfl[0] = &fl;
	if ( pBlock )
	    xfl[1] = pBlock->getTriggerValueList();
	else
	    xfl[1] = 0;
	xfl[2] = 0; // terminate in any case

	ListT<CegoSelect*> queryList;
	pPred->getSelectQueryList(queryList);
	CegoSelect **pSelect = queryList.First();
	while ( pSelect )
	{
	    (*pSelect)->setParentJoinBuf(xfl);
	    pSelect = queryList.Next();
	}

	pPred->analyzeSelect();
	
	// we have to resolve external references in a second step, since they are handled with lower priority
	pSelect = queryList.First();
	while ( pSelect )
	{
	    // before evaluating external table references, we have to prepare to resolve native query attributes first
	    (*pSelect)->prepare();	 
	    (*pSelect)->evalExtTableReferences(&oe, fl);
	    pSelect = queryList.Next();
	}

	CegoAttrCond ac;
	CegoQueryHelper::AttrCondMatch m = CegoQueryHelper::checkAttrCond(ac, pPred, fl, &fl, 1, pBlock);

	CegoTableCursor *pTC = new CegoTableCursor(this, oe.getTabSetId(), oe.getTabName(), true);

	try
	{
	    CegoAttrCond::IndexMatch idxMatch = CegoAttrCond::INAPP;

	    if ( m != CegoQueryHelper::INAPP )
		idxMatch = pTC->setup(ac);
	    
	    if ( idxMatch == CegoAttrCond::INAPP ) 
	    {
		ListT<CegoField> ufl = (ListT<CegoField>)oe.getSchema();

		// we need to create an additional reference for evalPredicate method
		ListT<CegoField>* xufl[3];
		xufl[0] = &ufl;
		if ( pBlock )
		    xufl[1] = pBlock->getTriggerValueList();
		else
		    xufl[1] = 0;
		xufl[2] = 0; // terminate in any case
		
		CegoDataPointer dp;
		bool moreTuple;		 		
		moreTuple = pTC->getFirst(ufl, dp);		
		while (moreTuple && _isAborted == false)
		{		    
		    pPred->clearAttrCache();

		    if ( pPred->eval(0, 0, xufl, 0, pBlock))
		    {			
			if ( tid == 0 )
			{
			    // before deleting, we first have to skip to next valid tuple
			    ListT<CegoField> nfl = oe.getSchema();	    
			    CegoDataPointer ndp;
			    moreTuple = pTC->getNext(nfl, ndp);

			    deleteDataTableEntrySynced(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE, dp, ufl, idxList, btreeList, keyList, true, false, isSynced);
			    delCount++;
			    
			    if ( moreTuple )
			    {
				dp = ndp;
				ufl = nfl;
			    }			
			}
			else
			{
			    deleteDataTableEntrySynced(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE, dp, ufl, idxList, btreeList, keyList, true, false, isSynced);
			    delCount++;
			    moreTuple = pTC->getNext(ufl, dp);
			}
		    }
		    else
		    {
			moreTuple = pTC->getNext(ufl, dp);   
		    }
		}	       
	    }	    
	    else
	    {			
		ListT<CegoField> ufl = (ListT<CegoField>)oe.getSchema();

		// we need to create an additional reference for evalPredicate method
		ListT<CegoField>* xufl[2];
		xufl[0] = &ufl;
		xufl[1] = 0;

		bool moreTuple;
		
		CegoDataPointer dp;

		moreTuple = pTC->getFirst(ufl, dp);

		while (moreTuple && _isAborted == false)
		{
		    pPred->clearAttrCache();

		    if ( pPred->eval(0, 0, xufl, 0, pBlock))
		    {	
			if ( tid == 0 )
			{			    
			    // if we are not inside a transaction, 
			    // the index or btree object for the delete condition
			    // was modified and we have to reset the cursor
			    
			    pTC->abort();	
		 
			    // cout << "Deleting data table with index cursor ..." << dp << endl;	   
			    deleteDataTableEntrySynced(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE, dp, ufl, idxList, btreeList, keyList, true, false, isSynced);
			    delCount++;
			    
			    moreTuple = pTC->getFirst(ufl, dp);
			}
			else
			{
			    deleteDataTableEntrySynced(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE, dp, ufl, idxList, btreeList, keyList, true, false, isSynced);
			    delCount++;
			    moreTuple = pTC->getNext(ufl, dp);
			}		    
		    }    
		    else
		    {
			moreTuple = pTC->getNext(ufl, dp);   
		    }		   
		}
	    }
	}
	catch ( Exception e )
	{
	    delete pTC;
	    throw Exception(EXLOC, Chain("Cannot delete data table"), e);		
	}	    
    
	delete pTC;
	
	if ( _isAborted )
	{	    
	    throw Exception(EXLOC, Chain("Delete aborted by user"));
	}	
    }	
    
#ifdef CGDEBUG	
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Delete finished, delCount = ") + Chain(delCount));
#endif

    // commit delete record

    char *pLogBuf = 0;
    unsigned logBuflen = 0;

    CegoQueryHelper::encodeDelRec(oe.getTabAlias(), pPred, pBlock, pLogBuf, logBuflen);

    /*
      for the delete operation, we have to get the LSN AFTER successful operation
      otherwise, it may occur, that a checkpoint happens during the delete with a higher LSN
      and so the operation is lost
    */
    
    lr.setLSN(_pDBMng->nextLSN(oe.getTabSetId()));
    lr.setData(pLogBuf);
    lr.setDataLen(logBuflen);
    
    _pDBMng->logIt(oe.getTabSetId(), lr, _pLockHandle);
    
    if ( logBuflen > 0 )
	free ( pLogBuf );
    
    return delCount;
}

void CegoTableManager::deleteDataTableEntrySynced(unsigned tabSetId, const Chain& tableName, CegoObject::ObjectType type, 
						  const CegoDataPointer& dp, const ListT<CegoField>& fvl, 
						  const ListT<CegoTableObject>& idxList,
						  const ListT<CegoBTreeObject>& btreeList,
						  const ListT<CegoKeyObject>& keyList, 
						  bool doCheckKey, bool doIgnoreIndexError, bool isSynced)
{
    unsigned long long recLock = 0;
    
    try
    {	    
	recLock = _pLockHandle->lockRecord(dp, CegoLockHandler::WRITE);
	
	deleteDataTableEntry(tabSetId, tableName, type, dp, fvl, idxList, btreeList, keyList, doCheckKey, doIgnoreIndexError);
	
	_pLockHandle->unlockRecord(recLock);
    }	    
    catch ( Exception e )
    {	    
	if ( recLock )
	    _pLockHandle->unlockRecord(recLock);	
	throw Exception(EXLOC, Chain("Cannot delete data table entry synced"), e);
    }   
}

bool CegoTableManager::deleteDataTableEntry(unsigned tabSetId, const Chain& tableName,
					    CegoObject::ObjectType type, 
					    const CegoDataPointer& dp,
					    const ListT<CegoField>& fvl,
					    const ListT<CegoTableObject>& idxList,
					    const ListT<CegoBTreeObject>& btreeList,
					    const ListT<CegoKeyObject>& keyList, 
					    bool doCheckKey, bool doIgnoreIndexError)
{
    if ( doCheckKey )
	if ( keyReferenceExists(tabSetId, tableName, fvl, keyList) )
	    throw Exception(EXLOC, Chain("Constraint violation on foreign key"));
    
    // we just delete entries on committed tuples
    if ( getTID(tabSetId) == 0 )
    {
	// delete index entries
	
	CegoTableObject* pOE = idxList.First();
	while (pOE)
	{
	    if ( pOE->isValid()
		 && ( pOE->getType() == CegoObject::AVLTREE 
		      || pOE->getType() == CegoObject::UAVLTREE
		      || pOE->getType() == CegoObject::PAVLTREE ) )		
	    {
		char p[TABMNG_MAXINDEXVALUE];
		unsigned len = TABMNG_MAXINDEXVALUE;
		unsigned idxLen;
		
		extractIndexValue(fvl, pOE->getSchema(), p, len, idxLen);

		try
		{
		    CegoAVLIndexManager idxMng(this);
		    idxMng.deleteIndexTable(tabSetId, tableName, type, pOE->getName(), pOE->getType(), pOE->getSchema(), dp, p, idxLen, true);		    
		}
		catch ( Exception e )
		{
		    if ( doIgnoreIndexError == false )
			throw Exception(EXLOC, Chain("Cannot delete data table entry"), e);  
		}
	    }
	    pOE = idxList.Next();
	}

	// delete btree entries
	
	CegoBTreeObject* pBTO = btreeList.First();
	while (pBTO)
	{
	    if (pBTO->getType() == CegoObject::BTREE
		|| pBTO->getType() == CegoObject::UBTREE
		|| pBTO->getType() == CegoObject::PBTREE )
		
	    {		
		CegoBTreeValue btv;
		btv.valueFromSchema(fvl, pBTO->getSchema());
		
		try
		{
		    CegoBTreeManager btreeMng(this, pBTO);
		    btreeMng.deleteBTree(btv, dp, getTID(tabSetId));
		}
		catch ( Exception e )
		{
		    if ( doIgnoreIndexError == false )
			throw Exception(EXLOC, Chain("Cannot delete data table entry"), e);
		}
	    }
	    pBTO = btreeList.Next();
	}

        // delete blob and clob entries
	CegoField *pF = fvl.First();
	
	while ( pF)
	{
	    if ( pF->getValue().getType() == BLOB_TYPE && pF->getValue().getValue() != 0 )
	    {
		PageIdType pageId;
		memcpy(&pageId, pF->getValue().getValue(), sizeof(PageIdType));
		
		decreaseBlobRef(tabSetId, pageId);
	    }

	    if ( pF->getValue().getType() == CLOB_TYPE && pF->getValue().getValue() != 0 )
	    {
		PageIdType pageId;
		memcpy(&pageId, pF->getValue().getValue(), sizeof(PageIdType));
		
		decreaseClobRef(tabSetId, pageId);
	    }
	    
	    pF = fvl.Next();
	}

	unsigned numTries=0;
	bool isDeleted=false;
	while ( isDeleted == false )
	{
	    try
	    {
#ifdef CGDEBUG	
		_pDBMng->log(_modId, Logger::DEBUG, Chain("Deleting tuple"));
#endif
		deleteData(type, tabSetId, dp);
		isDeleted=true;
	    }
	    catch ( Exception e )
	    {
		Chain msg;
		e.pop(msg);
		_pDBMng->log(_modId, Logger::NOTICE, Chain("Retry delete after :  ") + msg);
		
		if ( numTries == LCKMNG_NUMLOCKTRIES )
		{
		    throw Exception(EXLOC, msg);
		}
		numTries++;
	    }			
	}

	return true;
    }
    else //  getTID(tabSetId) != 0 
    {
	unsigned long long tid;
	unsigned long long tastep;
	CegoTupleState ts;

	bool tupleTouched = false;
		    	    
	getTupleInfo(tabSetId, dp, tid, tastep, ts);
	
	// is tuple untouched or already modified by the same transaction
	if ( getTID(tabSetId) == tid || tid == 0 )
	{	    	   	    
	    if ( ts == CegoTupleState::INSERTED )
	    {
		// tuple was inserted by this transaction, we just set tuple info to avoid double delete
		setTupleInfo(tabSetId, dp, getTID(tabSetId), getTAStep(tabSetId), CegoTupleState::OBSOLETE);
	    }
	    else if ( ts == CegoTupleState::COMMITTED )
	    {
		// tuple was not touched by this transaction, mark tuple as deleted and create rb entry
		_pTM->newRBEntry(tabSetId, getTID(tabSetId), dp.getPageId(), dp.getOffset(), tableName);
		setTupleInfo(tabSetId, dp, getTID(tabSetId), getTAStep(tabSetId), CegoTupleState::DELETED);
	    }
	    else if ( ts == CegoTupleState::OBSOLETE || ts == CegoTupleState::DELETED )
	    {
		// tuple already covered by thsi transaction
	    }
	    
	    tupleTouched = true;
	}
	
	return tupleTouched;
    }
}

void CegoTableManager::truncateTable(unsigned tabSetId, const Chain& tableName)
{
#ifdef CGDEBUG	
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Start of call truncateTable(") + Chain(tabSetId)
		 + Chain(",") + tableName + Chain(")"));
		
#endif

    if ( getTID(tabSetId) > 0 )
    {
	Chain msg = Chain("Truncate in a transaction not allowed"); 
	throw Exception(EXLOC, msg);	
    }
    
    if  ( _pTM->hasOpenTransaction(tabSetId, tableName) )
    {
	Chain msg = Chain("Table ") + tableName + Chain(" still has open transactions"); 
	throw Exception(EXLOC, msg);
    }

    ListT<CegoTableObject> idxList;
    ListT<CegoBTreeObject> btreeList;
    ListT<CegoKeyObject> keyList;
    ListT<CegoCheckObject> checkList;
    ListT<CegoTriggerObject> triggerList;
    ListT<CegoAliasObject> aliasList;

    unsigned numInvalid;
    
    getObjectListByTable(tabSetId, tableName, idxList, btreeList, keyList, checkList, triggerList, aliasList, numInvalid);

    CegoKeyObject *pKey = keyList.First();
    while ( pKey )
    {
	if ( pKey->getRefTable() == tableName )
	{	    
	    CegoTableCursor* pTC = new CegoTableCursor(this, tabSetId, pKey->getTabName(), true);
		
	    try
	    {
		bool moreTuple;
		CegoDataPointer dp;
		ListT<CegoField> fl;
		moreTuple = pTC->getFirst(fl, dp);
	    
		if  (moreTuple)
		{
		    throw Exception(EXLOC, Chain("Cannot truncate key reference table with existing references"));		    		    
		}

		delete pTC;
	    }	
	    catch ( Exception e )
	    {
		delete pTC;
		throw Exception(EXLOC, Chain("Cannot truncate table"), e);
	    }
	}
	pKey = keyList.Next();
    }

    CegoTableObject *pIO = idxList.First();
    while ( pIO )
    {
#ifdef CGDEBUG	
	_pDBMng->log(_modId, Logger::DEBUG, Chain("Truncating index ") + pIO->getName() + Chain(" ..."));
#endif

	truncateObject(tabSetId, pIO->getName(), pIO->getType());		    	
	pIO = idxList.Next();
    }

    CegoBTreeObject *pBTO = btreeList.First();
    while ( pBTO )
    {
#ifdef CGDEBUG	
	_pDBMng->log(_modId, Logger::DEBUG, Chain("Truncating btree ") + pBTO->getName() + Chain(" ..."));
#endif
	
	truncateObject(tabSetId, pBTO->getName(), pBTO->getType());
	
	pBTO = btreeList.Next();
    }

    // check for blobs and remove 

    CegoTableObject oe;
    getObject(tabSetId, tableName, CegoObject::TABLE, oe);
    ListT<CegoField> fl = oe.getSchema();
    
    bool hasXlobField = false;
    CegoField *pF = fl.First();
    while ( pF )
    {
	if ( pF->getType() == BLOB_TYPE || pF->getType() == CLOB_TYPE )
	    hasXlobField = true;
	pF = fl.Next();
    }
	
    if ( hasXlobField )
    {
	CegoTableCursor* pTC = new CegoTableCursor(this, tabSetId, tableName, true);

	try
	{
	    bool moreTuple;
	    CegoDataPointer dp;
	    moreTuple = pTC->getFirst(fl, dp);
	    
	    while (moreTuple)
	    {	
		CegoField *pF = fl.First();
		while ( pF )
		{
		    if ( pF->getType() == BLOB_TYPE && pF->getValue().getValue() != 0 )
		    {
			PageIdType pageId;
			memcpy(&pageId, pF->getValue().getValue(), sizeof(PageIdType));
			
#ifdef CGDEBUG	
			_pDBMng->log(_modId, Logger::DEBUG, Chain("Releasing blob [") + Chain(pageId) + Chain("]"));
#endif

			decreaseBlobRef(tabSetId, pageId);
		    }

		    if ( pF->getType() == CLOB_TYPE && pF->getValue().getValue() != 0 )
		    {
			PageIdType pageId;
			memcpy(&pageId, pF->getValue().getValue(), sizeof(PageIdType));
			
#ifdef CGDEBUG	
			_pDBMng->log(_modId, Logger::DEBUG, Chain("Releasing clob [") + Chain(pageId) + Chain("]"));
#endif

			decreaseClobRef(tabSetId, pageId);
		    }
	    
		    pF = fl.Next();
		}
		moreTuple = pTC->getNext(fl, dp);	    
	    }
	    delete pTC;
	}
	catch ( Exception e )
	{
	    delete pTC;
	    throw Exception(EXLOC, Chain("Cannot truncate table"), e);
	}
    }

#ifdef CGDEBUG	
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Truncating table ") + tableName + Chain(" ..."));
#endif

    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));

    truncateObject(tabSetId, tableName, CegoObject::TABLE);

    // create log entry
    lr.setObjectInfo(tableName, CegoObject::TABLE);
    lr.setAction(CegoLogRecord::LOGREC_TRUNCATE);    
    lr.setData(0);
    lr.setDataLen(0);

    _pDBMng->logIt(tabSetId, lr, _pLockHandle);
}

void CegoTableManager::dropObjectSynced(unsigned tabSetId, const Chain& objName, CegoObject::ObjectType type)
{    
    Chain useName;
    CegoObject::ObjectType useType;

    if ( type == CegoObject::AVLTREE 
	 || type == CegoObject::UAVLTREE 
	 || type == CegoObject::PAVLTREE )
    {
	CegoTableObject io;
	getObject(tabSetId, objName, type, io);
	useName = io.getTabName();	
	useType=CegoObject::TABLE;

	// We still have to check, if any foreign key reference exists
	// If so, we do not allow to remove
	if ( io.getType() == CegoObject::PAVLTREE )
	{
	    ListT<CegoTableObject> checkIdxList;
	    ListT<CegoBTreeObject> checkBTreeList;
	    ListT<CegoKeyObject> checkKeyList;
	    ListT<CegoCheckObject> checkList;
	    ListT<CegoTriggerObject> triggerList;
	    ListT<CegoAliasObject> aliasList;
	    unsigned numInvalid;
	    
	    getObjectListByTable(tabSetId, useName, checkIdxList, checkBTreeList, checkKeyList, checkList, triggerList, aliasList, numInvalid);
	    CegoKeyObject *pKey = checkKeyList.First();
	    while ( pKey )
	    {
		if ( pKey->getRefTable() == useName )
		{
		    throw Exception(EXLOC, Chain("Cannot drop primary avltree with existing key reference"));		    
		}
		pKey = checkKeyList.Next();
	    }
	}	
    }
    else if ( type == CegoObject::BTREE
	 || type == CegoObject::UBTREE
	 || type == CegoObject::PBTREE )
    {
	CegoBTreeObject bto;
	getObject(tabSetId, objName, type, bto);
	useName = bto.getTabName();	
	useType=CegoObject::TABLE;

	// We still have to check, if any foreign key reference exists
	// If so, we do not allow to remove
	if ( bto.getType() == CegoObject::PBTREE )
	{
	    ListT<CegoTableObject> checkIdxList;
	    ListT<CegoBTreeObject> checkBTreeList;
	    ListT<CegoKeyObject> checkKeyList;
	    ListT<CegoCheckObject> checkList;
	    ListT<CegoTriggerObject> triggerList;
	    ListT<CegoAliasObject> aliasList;
	    unsigned numInvalid;
	    
	    getObjectListByTable(tabSetId, useName, checkIdxList, checkBTreeList, checkKeyList, checkList, triggerList, aliasList, numInvalid);
	    CegoKeyObject *pKey = checkKeyList.First();
	    while ( pKey )
	    {
		if ( pKey->getRefTable() == useName )
		{
		    throw Exception(EXLOC, Chain("Cannot drop primary btree with existing key reference"));		    
		}
		pKey = checkKeyList.Next();
	    }
	}
    }
    else if ( type == CegoObject::TABLE )
    {
	useName = objName;
	useType=type;
    }
    else if ( type == CegoObject::PROCEDURE 
	      || type == CegoObject::VIEW )
    {
	useName = objName;
	useType=type;
    }
    else if ( type == CegoObject::FKEY )
    {
	CegoKeyObject ko;
	getObject(tabSetId, objName, type, ko);
	useName = ko.getTabName();       
	useType=CegoObject::TABLE;	
    }
    else if ( type == CegoObject::CHECK )
    {
	CegoCheckObject co;
	getObject(tabSetId, objName, type, co);
	useName = co.getTabName(); 
	useType=CegoObject::TABLE;		
    }
    else if ( type == CegoObject::TRIGGER )
    {
	CegoTriggerObject to;
	getObject(tabSetId, objName, type, to);
	useName = to.getTabName(); 
	useType=CegoObject::TABLE;		
    }
    else if ( type == CegoObject::ALIAS )
    {
	// for alias objects, we allow drop without synching with corresponding table
	useName = objName;
	useType=type;
    }

    else
    {
	throw Exception(EXLOC, Chain("Invalid object type"));
    }
    
    _pDBMng->useObject(tabSetId, useName, useType, CegoDatabaseManager::EXCLUSIVE_WRITE, this);
    
    try
    {	
	switch ( type )
	{
	case CegoObject::TABLE:
	    dropTable(tabSetId, objName);
	    break;
	case CegoObject::AVLTREE:
	case CegoObject::UAVLTREE:
	case CegoObject::PAVLTREE:
	    dropIndex(tabSetId, objName);
	    break;
	case CegoObject::BTREE:
	case CegoObject::UBTREE:
	case CegoObject::PBTREE:
	    dropBTree(tabSetId, objName);
	    break;
	case CegoObject::VIEW:
	    dropView(tabSetId, objName);
	    break;
	case CegoObject::PROCEDURE:
	    dropProcedure(tabSetId, objName);
	    break;
	case CegoObject::FKEY:
	    dropFKey(tabSetId, objName);
	    break;
	case CegoObject::CHECK:
	    dropCheck(tabSetId, objName);
	    break;
	case CegoObject::TRIGGER:
	    dropTrigger(tabSetId, objName);
	    break;
	case CegoObject::ALIAS:
	    dropAlias(tabSetId, objName);
	    break;
	case CegoObject::SYSTEM:
	case CegoObject::RBSEG:
	case CegoObject::JOIN:
	case CegoObject::UNDEFINED:
	    throw Exception(EXLOC, "Invalid object type for drop");
	}
    }
    catch ( Exception e )
    {	
	_pDBMng->unuseObject(tabSetId, useName, useType);
	throw Exception(EXLOC, Chain("Cannot drop object synced"), e);
    }

    _pDBMng->removeObject(tabSetId, objName, type);
    
    if ( useName != objName ) 
     	_pDBMng->unuseObject(tabSetId, useName, useType);
}

void CegoTableManager::dropTable(unsigned tabSetId, 
				 const Chain& tableName)    
{
#ifdef CGDEBUG	
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Start of call dropTable(") + Chain(tabSetId)
		 + Chain(",") + tableName + Chain(")"));
		
#endif

    if ( getTID(tabSetId) > 0 )
    {
	Chain msg = Chain("Drop in a transaction not allowed"); 
	throw Exception(EXLOC, msg);	
    }
    
    if  ( _pTM->hasOpenTransaction(tabSetId, tableName) )
    {
	Chain msg = Chain("Table ") + tableName + Chain(" still has open transactions"); 
	throw Exception(EXLOC, msg);
    }

    ListT<CegoTableObject> idxList;
    ListT<CegoBTreeObject> btreeList;
    ListT<CegoKeyObject> keyList;
    ListT<CegoCheckObject> checkList;
    ListT<CegoTriggerObject> triggerList;
    ListT<CegoAliasObject> aliasList;
    unsigned numInvalid;
       
    getObjectListByTable(tabSetId, tableName, idxList, btreeList, keyList, checkList, triggerList, aliasList, numInvalid);

    CegoKeyObject *pKey = keyList.First();
    while ( pKey )
    {
	if ( pKey->getRefTable() == tableName && pKey->getTabName() != tableName ) 
	{
	    throw Exception(EXLOC, Chain("Cannot drop table with existing foreign key reference"));		    
	}
	pKey = keyList.Next();
    }

    CegoTableObject *pIO = idxList.First();
    while ( pIO )
    {
	if ( pIO->getType() == CegoObject::AVLTREE 
	     || pIO->getType() == CegoObject::UAVLTREE
	     || pIO->getType() == CegoObject::PAVLTREE )
	{
#ifdef CGDEBUG	
	    _pDBMng->log(_modId, Logger::DEBUG, Chain("Dropping index ") + pIO->getName() + Chain(" ..."));
#endif

	    removeObject(tabSetId, pIO->getName(), pIO->getType());
	    _pDBMng->removeObject(tabSetId, pIO->getName(), pIO->getType());	    
	}
	pIO = idxList.Next();
    }

    CegoBTreeObject *pBTO = btreeList.First();
    while ( pBTO )
    {
	if ( pBTO->getType() == CegoObject::BTREE 
	     || pBTO->getType() == CegoObject::UBTREE
	     || pBTO->getType() == CegoObject::PBTREE )
	{
#ifdef CGDEBUG	
	    _pDBMng->log(_modId, Logger::DEBUG, Chain("Dropping btree ") + pBTO->getName() + Chain(" ..."));
#endif
	   
	    removeObject(tabSetId, pBTO->getName(), pBTO->getType());
	    _pDBMng->removeObject(tabSetId, pBTO->getName(), pBTO->getType());
	}
	pBTO = btreeList.Next();
    }

    CegoKeyObject *pKO = keyList.First();
    while ( pKO )
    {
#ifdef CGDEBUG	
	_pDBMng->log(_modId, Logger::DEBUG, Chain("Dropping key ") + pKO->getName() + Chain(" ..."));
#endif	
	removeObject(tabSetId, pKO->getName(), pKO->getType());
	_pDBMng->removeObject(tabSetId, pKO->getName(), pKO->getType());
	
	pKO = keyList.Next();
    }

    CegoCheckObject *pCO = checkList.First();
    while ( pCO )
    {
#ifdef CGDEBUG	
	_pDBMng->log(_modId, Logger::DEBUG, Chain("Dropping check ") + pCO->getName() + Chain(" ..."));
#endif
	
	removeObject(tabSetId, pCO->getName(), pCO->getType());
	_pDBMng->removeObject(tabSetId, pCO->getName(), pCO->getType());
	
	pCO = checkList.Next();
    }

    CegoTriggerObject *pTO = triggerList.First();
    while ( pTO )
    {
#ifdef CGDEBUG	
	_pDBMng->log(_modId, Logger::DEBUG, Chain("Dropping trigger ") + pTO->getName() + Chain(" ..."));
#endif
	
	removeObject(tabSetId, pTO->getName(), pTO->getType());
	_pDBMng->removeObject(tabSetId, pTO->getName(), pTO->getType());
	
	pTO = triggerList.Next();
    }

    CegoAliasObject *pAO = aliasList.First();
    while ( pAO )
    {
#ifdef CGDEBUG	
	_pDBMng->log(_modId, Logger::DEBUG, Chain("Dropping alias ") + pAO->getName() + Chain(" ..."));
#endif
	
	removeObject(tabSetId, pAO->getName(), pAO->getType());
	_pDBMng->removeObject(tabSetId, pAO->getName(), pAO->getType());
	
	pAO = aliasList.Next();
    }

    // check for blobs and remove 
    
    CegoTableObject oe;
    getObject(tabSetId, tableName, CegoObject::TABLE, oe);
    ListT<CegoField> fl = oe.getSchema();
    
    bool hasXlobField = false;
    CegoField *pF = fl.First();
    while ( pF )
    {
	if ( pF->getType() == BLOB_TYPE || pF->getType() == CLOB_TYPE )
	    hasXlobField = true;
	pF = fl.Next();
    }

    if ( hasXlobField )
    {       	
	CegoTableCursor* pTC = new CegoTableCursor(this, tabSetId, tableName, true);

	try
	{
	    bool moreTuple;
	    CegoDataPointer dp;
	    moreTuple = pTC->getFirst(fl, dp);
	    
	    while (moreTuple)
	    {	
		CegoField *pF = fl.First();
		while ( pF )
		{
		    if ( pF->getType() == BLOB_TYPE && pF->getValue().getValue() != 0 )
		    {
			PageIdType pageId;
			memcpy(&pageId, pF->getValue().getValue(), sizeof(PageIdType));
			
#ifdef CGDEBUG	
			_pDBMng->log(_modId, Logger::DEBUG, Chain("Releasing blob [") + Chain(pageId) + Chain("]"));
#endif

			decreaseBlobRef(tabSetId, pageId);
		    }

		    if ( pF->getType() == CLOB_TYPE && pF->getValue().getValue() != 0 )
		    {
			PageIdType pageId;
			memcpy(&pageId, pF->getValue().getValue(), sizeof(PageIdType));
			
#ifdef CGDEBUG	
			_pDBMng->log(_modId, Logger::DEBUG, Chain("Releasing clob [") + Chain(pageId) + Chain("]"));
#endif

			decreaseClobRef(tabSetId, pageId);
		    }
	    
		    pF = fl.Next();
		}
		moreTuple = pTC->getNext(fl, dp);	    
	    }
	    delete pTC;
	}
	catch ( Exception e )
	{
	    delete pTC;
	    throw Exception(EXLOC, Chain("Cannot drop table"), e);	    
	}
    }

#ifdef CGDEBUG	
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Dropping table ") + tableName + Chain(" ..."));
#endif

    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));
    
    removeObject(tabSetId, tableName, CegoObject::TABLE);

    // create log entry
    lr.setObjectInfo(tableName, CegoObject::TABLE);
    lr.setAction(CegoLogRecord::LOGREC_DROP);    
    lr.setData(0);
    lr.setDataLen(0);

    _pDBMng->logIt(tabSetId, lr, _pLockHandle);
}

void CegoTableManager::dropIndex(unsigned tabSetId, const Chain& idxName)
{
    if ( getTID(tabSetId) > 0 )
    {
	Chain msg = Chain("Drop in a transaction not allowed"); 
	throw Exception(EXLOC, msg);	
    }

    CegoObject::ObjectType idxType = CegoObject::AVLTREE;
    
    if ( ! objectExists(tabSetId, idxName, idxType ) )
    {
	Chain msg = "Unknown index " + idxName; 
	throw Exception(EXLOC, msg);
    }

    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));
    
    removeObject(tabSetId, idxName, idxType);

    // create log entry
    lr.setObjectInfo(idxName, idxType);
    lr.setAction(CegoLogRecord::LOGREC_DROP);    
    lr.setData(0);
    lr.setDataLen(0);

    _pDBMng->logIt(tabSetId, lr, _pLockHandle);
}

void CegoTableManager::dropBTree(unsigned tabSetId, const Chain& btreeName)
{
    if ( getTID(tabSetId) > 0 )
    {
	Chain msg = Chain("Drop in a transaction not allowed"); 
	throw Exception(EXLOC, msg);	
    }

    CegoObject::ObjectType btType = CegoObject::BTREE;

    if ( ! objectExists(tabSetId, btreeName, btType ) )
    {
	Chain msg = "Unknown btree " + btreeName; 
	throw Exception(EXLOC, msg);
    }

    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));
    
    removeObject(tabSetId, btreeName, btType);

    // create log entry
    lr.setObjectInfo(btreeName, btType);
    lr.setAction(CegoLogRecord::LOGREC_DROP);    
    lr.setData(0);
    lr.setDataLen(0);

    _pDBMng->logIt(tabSetId, lr, _pLockHandle);
}

void CegoTableManager::dropView(unsigned tabSetId, const Chain& viewName)
{
    if ( getTID(tabSetId) > 0 )
    {
	Chain msg = Chain("drop in a transaction not allowed"); 
	throw Exception(EXLOC, msg);	
    }

    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));
    
    removeObject(tabSetId, viewName, CegoObject::VIEW);

    // create log entry
    lr.setObjectInfo(viewName, CegoObject::VIEW);
    lr.setAction(CegoLogRecord::LOGREC_DROP);    
    lr.setData(0);
    lr.setDataLen(0);

    _pDBMng->logIt(tabSetId, lr, _pLockHandle);
}

void CegoTableManager::dropProcedure(unsigned tabSetId, const Chain& procName)
{
    if ( getTID(tabSetId) > 0 )
    {
	Chain msg = Chain("drop in a transaction not allowed"); 
	throw Exception(EXLOC, msg);	
    }

    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));
    
    removeObject(tabSetId, procName, CegoObject::PROCEDURE);

    // create log entry
    lr.setObjectInfo(procName, CegoObject::PROCEDURE);
    lr.setAction(CegoLogRecord::LOGREC_DROP);    
    lr.setData(0);
    lr.setDataLen(0);
    
    _pDBMng->logIt(tabSetId, lr, _pLockHandle);
}

void CegoTableManager::dropFKey(unsigned tabSetId, const Chain& fkey)
{
    if ( getTID(tabSetId) > 0 )
    {
	Chain msg = Chain("drop in a transaction not allowed"); 
	throw Exception(EXLOC, msg);	
    }

    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));
    
    removeObject(tabSetId, fkey, CegoObject::FKEY);

    // create log entry
    lr.setObjectInfo(fkey, CegoObject::FKEY);
    lr.setAction(CegoLogRecord::LOGREC_DROP);    
    lr.setData(0);
    lr.setDataLen(0);

    _pDBMng->logIt(tabSetId, lr, _pLockHandle);
}

void CegoTableManager::dropCheck(unsigned tabSetId, const Chain& check)
{
    if ( getTID(tabSetId) > 0 )
    {
	Chain msg = Chain("drop in a transaction not allowed"); 
	throw Exception(EXLOC, msg);	
    }
    
    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));
    
    removeObject(tabSetId, check, CegoObject::CHECK);

    // create log entry
    lr.setObjectInfo(check, CegoObject::CHECK);
    lr.setAction(CegoLogRecord::LOGREC_DROP);    
    lr.setData(0);
    lr.setDataLen(0);

    _pDBMng->logIt(tabSetId, lr, _pLockHandle);
}

void CegoTableManager::dropTrigger(unsigned tabSetId, const Chain& trigger)
{
    if ( getTID(tabSetId) > 0 )
    {
	Chain msg = Chain("drop in a transaction not allowed"); 
	throw Exception(EXLOC, msg);	
    }
	
    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));

    removeObject(tabSetId, trigger, CegoObject::TRIGGER);

    // create log entry
    lr.setObjectInfo(trigger, CegoObject::TRIGGER);
    lr.setAction(CegoLogRecord::LOGREC_DROP);    
    lr.setData(0);
    lr.setDataLen(0);

    _pDBMng->logIt(tabSetId, lr, _pLockHandle);
}

void CegoTableManager::dropAlias(unsigned tabSetId, const Chain& aliasName)
{
    if ( getTID(tabSetId) > 0 )
    {
	Chain msg = Chain("drop in a transaction not allowed"); 
	throw Exception(EXLOC, msg);	
    }
	
    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));

    removeObject(tabSetId, aliasName, CegoObject::ALIAS);

    // create log entry
    lr.setObjectInfo(aliasName, CegoObject::ALIAS);
    lr.setAction(CegoLogRecord::LOGREC_DROP);    
    lr.setData(0);
    lr.setDataLen(0);

    _pDBMng->logIt(tabSetId, lr, _pLockHandle);
}

void CegoTableManager::correctTableSet(unsigned tabSetId, bool doSync)
{
    ListT<Chain> tabList;
    getObjectList(tabSetId, CegoObject::TABLE, tabList);
    
    Chain *pTableName = tabList.First();
    while ( pTableName )
    {
	_pDBMng->log(_modId, Logger::NOTICE, Chain("Post correction for table ") + *pTableName);
	correctIndexForTable(tabSetId, *pTableName, doSync, false);
	
	pTableName = tabList.Next();
    }    
}

void CegoTableManager::correctIndexForTable(unsigned tabSetId, const Chain& tableName, bool doSync, bool doForce)
{
    ListT<CegoTableObject> idxList;
    ListT<CegoBTreeObject> btreeList;
    ListT<CegoKeyObject> keyList;
    ListT<CegoCheckObject> checkList;
    ListT<CegoTriggerObject> triggerList;
    ListT<CegoAliasObject> aliasList;
    unsigned numInvalid;
	
    setIgnoreInvalid(false);
    getObjectListByTable(tabSetId, tableName, idxList, btreeList, keyList, checkList, triggerList, aliasList, numInvalid);
	
    // correct indexes
    CegoTableObject *pIdx = idxList.First();
    while ( pIdx ) 
    {	
	if ( pIdx->isValid() == false || doForce )
	{			
	    dropIndex(tabSetId, pIdx->getName());
	    bool isCached=false;
	    createIndexTable(tabSetId, pIdx->getName(), pIdx->getTabName(), pIdx->getSchema(), pIdx->getType(), isCached);
	    _pDBMng->log(_modId, Logger::NOTICE, Chain("Index ") + pIdx->getName() + Chain(" was corrected"));	
	}
	
	pIdx = idxList.Next();
    }
    
    // correct btrees
    CegoBTreeObject *pBTree = btreeList.First();
    while ( pBTree ) 
    {
	if ( pBTree->isValid() == false || doForce )
	{
	    dropBTree(tabSetId, pBTree->getName());
	    // to be defensive, we don't use btree cache for correction
	    bool isCached = false;
	    createBTree(tabSetId, pBTree->getName(), pBTree->getTabName(), pBTree->getSchema(), pBTree->getType(), doSync, isCached);
	    _pDBMng->log(_modId, Logger::NOTICE, Chain("Btree ") + pBTree->getName() + Chain(" was corrected"));			
	}
	pBTree = btreeList.Next();
    }
}

unsigned CegoTableManager::cleanTableSet(unsigned tabSetId)
{
    ListT<Chain> tabList;
    getObjectList(tabSetId, CegoObject::TABLE, tabList);

    // int traceCount = 0;
    Chain *pTableName = tabList.First();
    while ( pTableName )
    {
	// traceCount +=
	traceObject(tabSetId, *pTableName, CegoObject::TABLE);

	CegoTableObject oe;
	getObject(tabSetId, *pTableName, CegoObject::TABLE, oe);

	bool traceLob = false;
	CegoField *pF = oe.getSchema().First();
	while ( pF && traceLob == false)
	{
	    if ( pF->getType() == CLOB_TYPE || pF->getType() == BLOB_TYPE )
	    {
		traceLob=true;
	    }
	    pF = oe.getSchema().Next();
	}

	if ( traceLob )
	{
	    CegoTableCursor tc(this, tabSetId, *pTableName);
	    ListT<CegoField> fl = oe.getSchema();
	    CegoDataPointer dp;
	
	    if ( tc.getFirst(fl, dp) )
	    {
		do 
		{
		    CegoField *pF = fl.First();
		    while ( pF )
		    {
			if ( pF->getValue().getType() == BLOB_TYPE
			     || pF->getValue().getType() == CLOB_TYPE  )
			{
			    PageIdType pageId;
			    memcpy(&pageId, pF->getValue().getValue(), sizeof(PageIdType));
			    // traceCount +=
			    traceObjectPages(tabSetId, pageId);
			}
			pF = fl.Next();
		    }		    
		}
		while ( tc.getNext(fl, dp) );
	    }
	}

	pTableName = tabList.Next();
    }

    ListT<Chain> avlList;
    getObjectList(tabSetId, CegoObject::AVLTREE, avlList);
    
    Chain *pAVL = avlList.First();
    while ( pAVL )
    {
	// traceCount +=
	traceObject(tabSetId, *pAVL, CegoObject::AVLTREE);
	pAVL = avlList.Next();
    }

    ListT<Chain> btreeList;
    getObjectList(tabSetId, CegoObject::BTREE, btreeList);
    
    Chain *pBTree = btreeList.First();
    while ( pBTree )
    {
	// traceCount +=
	traceObject(tabSetId, *pBTree, CegoObject::BTREE);
	pBTree = btreeList.Next();
    }
    
    return _pDBMng->cleanPages(_pLockHandle);
}

bool CegoTableManager::getFirstTuple(CegoObjectCursor* pC, ListT<CegoField>& fl, CegoDataPointer& dp)
{
    unsigned len;
    
    char* pc = (char*)pC->getFirst(len, dp);
    
    if ( pc && len > 0 )
    {
	unsigned long long tid;
	unsigned long long tastep; 
	CegoTupleState ts;

	unsigned toff = CegoQueryHelper::decodeTupleHeader(tid, tastep, ts, pc);

	char* tp = pc + toff;
	unsigned tlen = len - toff;
	
	if ( tid != 0 ) 
	{	    
	    if  ( ( ts == CegoTupleState::INSERTED && tid == getTID(pC->getTabSetId()) )
		  || ( ts == CegoTupleState::DELETED && tid != getTID(pC->getTabSetId()) ) )
	    {	
		CegoQueryHelper::decodeFVL(fl, tp, tlen);
	    }
	    else 
	    {
		return getNextTuple(pC, fl, dp);		
	    }	       
	}
	else
	{
	    CegoQueryHelper::decodeFVL(fl, tp, tlen);
	}

	return true;
    }
    return false;
}

bool CegoTableManager::getNextTuple(CegoObjectCursor* pC, ListT<CegoField>& fl, CegoDataPointer& dp)
{
    do
    {	
	unsigned len;
	char* pc = (char*)pC->getNext(len, dp);
	
	if ( pc && len > 0 )
	{	    
	    unsigned long long tid;
	    unsigned long long tastep;
	    CegoTupleState ts;

	    unsigned toff = CegoQueryHelper::decodeTupleHeader(tid, tastep, ts, pc);

	    char* tp = pc + toff;
	    unsigned tlen = len - toff;

	    if ( tid != 0 ) 
	    {
		if ( ( ts == CegoTupleState::INSERTED && tid == getTID(pC->getTabSetId()) )
		     || ( ts == CegoTupleState::DELETED && tid == getTID(pC->getTabSetId()) ) )
		{	
		    CegoQueryHelper::decodeFVL(fl, tp, tlen);
		    return true;
		}
	    }
	    else
	    {
		CegoQueryHelper::decodeFVL(fl, tp, tlen);
		return true;
	    }
	}
	else
	{
	    return false;
	}
    
    }  while ( 1 ) ;
}

void CegoTableManager::createIndexTableSynced(unsigned tabSetId, const Chain& indexName, const Chain& tableName, CegoObject::ObjectType type, ListT<CegoField>& idxList, bool isCached)
{
    if ( type == CegoObject::PAVLTREE
	 || type == CegoObject::UAVLTREE
	 || type == CegoObject::AVLTREE )
    {
	if ( isCached )
	{
	    Chain msg = "Cache option not supported for AVL tree";
	    throw Exception(EXLOC, msg);	    
	}
	
	_pDBMng->useObject(tabSetId, tableName, CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE_WRITE, this);
	
	try
	{
	    createAVLIndexTable(tabSetId, indexName, tableName, idxList, type);
	}
	catch ( Exception  e )
	{
	    _pDBMng->unuseObject(tabSetId, tableName, CegoObject::TABLE);
	    throw Exception(e);
	}
	_pDBMng->unuseObject(tabSetId, tableName, CegoObject::TABLE);	
    }
    else if ( type == CegoObject::PBTREE
	 || type == CegoObject::UBTREE
	 || type == CegoObject::BTREE )
    {
	createBTree(tabSetId, indexName, tableName, idxList, type, true, isCached);	
    } 
    
    _pDBMng->addObject(tabSetId, indexName, type);
}

void CegoTableManager::createPrimaryIndexTable(unsigned tabSetId, const Chain& indexName, const Chain& tableName, ListT<CegoField>& schema)
{
    CegoObject::ObjectType type = CegoObject::PBTREE;
    bool isCached=false;
    createIndexTable(tabSetId, indexName, tableName, schema, type, isCached);
}

void CegoTableManager::createIndexTable(unsigned tabSetId, const Chain& indexName, const Chain& tableName, const ListT<CegoField>& schema, CegoObject::ObjectType type, bool isCached)
{
    if ( type == CegoObject::PAVLTREE
	 || type == CegoObject::UAVLTREE
	 || type == CegoObject::AVLTREE )
    {
	if ( isCached )
	{
	    Chain msg = "Cache option not supported for AVL tree";
	    throw Exception(EXLOC, msg);	    
	}

	createAVLIndexTable(tabSetId, indexName, tableName, schema, type);
    }
    else if ( type == CegoObject::PBTREE
	 || type == CegoObject::UBTREE
	 || type == CegoObject::BTREE )
    {
	createBTree(tabSetId, indexName, tableName, schema, type, false, isCached);
    } 
    else
    {
	throw Exception(EXLOC, Chain("Unknown index type"));
    }
}

void CegoTableManager::createBTree(unsigned tabSetId, const Chain& btreeName, const Chain& tableName, const ListT<CegoField>& schema, CegoObject::ObjectType type, bool doSync, bool isCached)
{
    if ( getTID(tabSetId) > 0 )
    {
	Chain msg = Chain("create btree in a transaction not allowed"); 
	throw Exception(EXLOC, msg);	
    }

    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));
    
    CegoTableObject toe;
    
    getObject(tabSetId, tableName, CegoObject::TABLE, toe);

    CegoField* pF;

    // first we create a tableschema with the required attribute in the appropriate order
    ListT<CegoField> tableSchema;
    pF = toe.getSchema().First();
    while ( pF )
    {
	if ( schema.Find(CegoField(tableName, pF->getAttrName())))
	    tableSchema.Insert(*pF);	
	pF = toe.getSchema().Next();
    }
    
    pF = schema.First();
    while (pF)
    {
	CegoField* pSF = toe.getSchema().Find(CegoField(tableName, pF->getAttrName()));
	    
	if ( pSF )
	{
	    pF->setType(pSF->getType());
	    pF->setLength(pSF->getLength());
	    pF->setId(pSF->getId());		
	}
	else
	{
	    Chain msg = "Unknown field <" + pF->getAttrName()  + ">";
	    throw Exception(EXLOC, msg);	    
	}
	
	if ( type == CegoObject::PBTREE && pSF->isNullable() )
	{
	    Chain msg = "Primary btree attribute must be not nullable";
	    throw Exception(EXLOC, msg);
	}

	pF = schema.Next();
    }

    if ( doSync )
	_pDBMng->useObject(tabSetId, tableName, CegoObject::TABLE, CegoDatabaseManager::SHARED, this);

    CegoBTreeObject btoe(tabSetId, type, btreeName, schema, tableName);    
    CegoDataPointer sysEntry;

    try
    {
	createBTreeObject(btoe);	
    }
    catch ( Exception e )
    {       
	if ( doSync )
	    _pDBMng->unuseObject(tabSetId, tableName, CegoObject::TABLE);

	throw Exception(EXLOC, Chain("Create of btree failed"), e);
    }
        
    // building up index

    CegoObjectCursor* pC = 0;
    CegoBufferPage bp;
    CegoBTreeManager* pBTreeMng = 0;
	
    try
    {  
	// we have to keep the index object in buffer pool 
	getObjectWithFix(tabSetId, btreeName, type, btoe, bp);
	sysEntry = CegoDataPointer(bp.getPageId(), bp.getEntryPos());

	// create root node
	
	CegoBufferPage rootPage;
	getNewFilePage(rootPage, btoe.getTabSetId(), btoe.getType());   
	
	rootPage.setType(CegoBufferPage::BTREE_LEAF);
	CegoBTreeNode rootNode;
	rootNode.setPtr(rootPage.getChunkEntry(), rootPage.getChunkLen());
	rootNode.initNode();
	
	PageIdType dataPageId = rootPage.getPageId();

	btoe.setDataPageId(dataPageId);

	_pDBMng->bufferUnfix(rootPage, true, _pLockHandle);
	    	
	CegoDataPointer dp;
	pC = getObjectCursor(tabSetId, tableName, tableName, CegoObject::TABLE);
	bool moreTuple = getFirstTuple(pC, tableSchema, dp);
	
	pBTreeMng = new CegoBTreeManager(this, &btoe);

	if ( isCached )
	{
	    pBTreeMng->createCache();
	}     
	      
	while (moreTuple && _isAborted == false)
	{
	    CegoBTreeValue iv;

	    iv.valueFromSchema(tableSchema, schema);   
		
	    unsigned long long tid = 0;
	    pBTreeMng->insertBTree(dp, iv, tid);
	    
	    moreTuple = getNextTuple(pC, tableSchema, dp);
	}

	// we also can release the object cursor
	pC->abort();
	delete pC;
	pC = 0;

	if ( _isAborted )
	{	    
	    throw Exception(EXLOC, Chain("Btree creation aborted by user"));
	}

	if ( doSync )
	{
	    _pDBMng->unuseObject(tabSetId, tableName, CegoObject::TABLE);
	    _pDBMng->useObject(tabSetId, tableName, CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE_WRITE, this);
	}

	pBTreeMng->commit(sysEntry);

	if ( doSync )
	{
	    _pDBMng->unuseObject(tabSetId, tableName, CegoObject::TABLE);
	}	
    }
    catch ( Exception e )
    {
	if  ( bp.isFixed() )
	    _pDBMng->bufferUnfix(bp, true, _pLockHandle);
	
	if ( pC )
	{
	    pC->abort();
	    delete pC;
	}
	if ( pBTreeMng )
	{
	    pBTreeMng->rollback();
	    delete pBTreeMng;
	}
	
	dropBTree(tabSetId, btreeName);
       
	if ( doSync )
	    _pDBMng->unuseObject(tabSetId, tableName, CegoObject::TABLE);
	
	throw Exception(EXLOC, Chain("Create of btree failed") , e);
    }

    // now we can release the index root page
    _pDBMng->bufferUnfix(bp, true, _pLockHandle);

    delete pBTreeMng;

    // create log entry
    
    lr.setObjectInfo(btoe.getName(), btoe.getType());
    lr.setAction(CegoLogRecord::LOGREC_CREATE);
    
    char *buf;
    buf = (char*)malloc(btoe.getEntrySize());

    btoe.encode(buf);
    lr.setData(buf);
    lr.setDataLen(btoe.getEntrySize());
    // lr.setTID(0);

    _pDBMng->logIt(btoe.getTabSetId(), lr, _pLockHandle);

    free(buf);
}

void CegoTableManager::createAVLIndexTable(unsigned tabSetId, const Chain& indexName, const Chain& tableName, const ListT<CegoField>& schema, CegoObject::ObjectType type)
{
    if ( getTID(tabSetId) > 0 )
    {
	Chain msg = Chain("create avl index in a transaction not allowed"); 
	throw Exception(EXLOC, msg);	
    }

    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));
    
    CegoTableObject toe;

    getObject(tabSetId, tableName, CegoObject::TABLE, toe);

    CegoField* pF = schema.First();
    while (pF)
    {
	CegoField* pSF = toe.getSchema().Find(CegoField(tableName, pF->getAttrName()));
	    
	if ( pSF )
	{
	    pF->setType(pSF->getType());
	    pF->setLength(pSF->getLength());
	    pF->setId(pSF->getId());		
	}
	else
	{
	    Chain msg = "Unknown field <" + pF->getAttrName()  + ">";
	    throw Exception(EXLOC, msg);	    
	}
	
	if ( type == CegoObject::PAVLTREE && pSF->isNullable() )
	{
	    Chain msg = "Primary index attribute must be not nullable";
	    throw Exception(EXLOC, msg);
	}

	pF = schema.Next();
    }

    CegoTableObject ioe(tabSetId, type, indexName, schema, tableName);
    
    createTableObject(ioe);

    CegoAVLIndexEntry base;
    CegoDataPointer nil;
    
    base.initEntry(nil);
    
    base.setLeftBranch(nil);
    base.setParent(nil);
    base.setRightBranch(nil);
    
    CegoDataPointer dp = insertData(ioe, (char*)base.getPtr(), base.getLen(), true);
    
    // building up index

    CegoObjectCursor* pC = 0;
    CegoBufferPage bp;

    CegoAVLIndexManager idxMng(this);

    try
    {
	pC = getObjectCursor(tabSetId, tableName, tableName, CegoObject::TABLE);
    	
	// we have to keep the index object in buffer pool 
	getObjectWithFix(tabSetId, indexName, type, ioe, bp);
	
	CegoDataPointer dp;
	unsigned long long tid = 0;
	
	char idxBuf[TABMNG_MAXINDEXVALUE];	    

	ListT<CegoField> data = schema;
	bool moreTuple = getFirstTuple(pC, data, dp);
	
	bool isFirst = true;
	CegoDataPointer ritp;

	CegoDataPointer sysEntry(bp.getPageId(), bp.getEntryPos());

	while (moreTuple && _isAborted == false)
	{
	    // get Index len
	    unsigned idxLen = 0;
	    CegoField* pF = data.First();
	    while (pF)
	    {
		idxLen += pF->getValue().getLength() + sizeof(unsigned);
		pF = data.Next();
	    }
	    	    
	    char* idxPtr = idxBuf;
	    pF = data.First();
	    while (pF)
	    {
		unsigned len = pF->getValue().getLength();
		memcpy(idxPtr, &len, sizeof(unsigned));
		idxPtr+=sizeof(unsigned);
		if ( len > 0 )
		{
		    memcpy(idxPtr, pF->getValue().getValue(), len);	   
		    idxPtr += len;
		}
		pF = data.Next();
	    }

	    if ( isFirst )
	    {
		// since we have locked the index root page in bufferpool, we can call with no resolution of object entry
		idxMng.insertNativeIndexTable(ioe, sysEntry, dp, idxBuf, idxLen, tid, true, ritp);
		isFirst=false;
	    }
	    else
	    {		
		bool isUnique = false;
		if ( type == CegoObject::UAVLTREE || type == CegoObject::PAVLTREE )
		    isUnique = true;
		
		idxMng.insertIndexTable(ioe, sysEntry, ritp, isUnique, dp, idxBuf, idxLen, tid, true, true);
	    }
	    
	    moreTuple = getNextTuple(pC, data, dp);
	}    

	if ( _isAborted )
	{	    
	    throw Exception(EXLOC, Chain("Index creation aborted by user"));
	}	
    }
    catch ( Exception e )
    {
	if  ( bp.isFixed() )
	    _pDBMng->bufferUnfix(bp, true, _pLockHandle);
	if ( pC )
	    pC->abort();

	delete pC;
	dropIndex(tabSetId, indexName);
	
	throw Exception(EXLOC, Chain("Create of index failed"), e);
    }

    // now we can release the index root page
    _pDBMng->bufferUnfix(bp, true, _pLockHandle);

    // we also can release the object cursor
    pC->abort();

    delete pC;

    // create log entry
    lr.setObjectInfo(ioe.getName(), ioe.getType());
    lr.setAction(CegoLogRecord::LOGREC_CREATE);
    
    char *buf;
    buf = (char*)malloc(ioe.getEntrySize());

    ioe.encode(buf);
    lr.setData(buf);
    lr.setDataLen(ioe.getEntrySize());
    // lr.setTID(0);

    _pDBMng->logIt(ioe.getTabSetId(), lr, _pLockHandle);

    free(buf);
}

void CegoTableManager::createForeignKey(unsigned tabSetId, const Chain& fkey, const Chain& tableName, const ListT<CegoField>& keyList, const Chain& refTable, const ListT<CegoField>& refList)
{		
    if ( getTID(tabSetId) > 0 )
    {
	Chain msg = Chain("create foreign key in a transaction not allowed"); 
	throw Exception(EXLOC, msg);	
    }

    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));
    
    CegoObjectCursor* pC = 0;
    
    try
    {	
	// check if key references primary key
	
	ListT<CegoTableObject> checkIdxList;
	ListT<CegoBTreeObject> checkBTreeList;
	ListT<CegoKeyObject> checkKeyList;
	ListT<CegoCheckObject> checkList;
	ListT<CegoTriggerObject> triggerList;
	ListT<CegoAliasObject> aliasList;
	unsigned numInvalid;

	getObjectListByTable(tabSetId, refTable, checkIdxList, checkBTreeList, checkKeyList, checkList, triggerList, aliasList, numInvalid);
	if ( numInvalid > 0 )
	{
	    throw Exception(EXLOC, Chain("Cannot create foreign key on table with invalid index"));
	}
	
	CegoTableObject *pIO = checkIdxList.First();
	bool idxFound = false;
	while ( pIO && idxFound == false)
	{
	    if ( pIO->getType() == CegoObject::PAVLTREE )
	    {
		if ( pIO->getSchema().Size() == keyList.Size() )
		{		    
		    CegoField *pK = refList.First();
		    idxFound = true;
		    while ( pK && idxFound )
		    {
			if ( pIO->getSchema().Find(*pK) )
			{
			    pK = refList.Next();			
			}
			else
			{
			    idxFound = false;
			}		    
		    }
		}
		// just one primary index can be found
		pIO = 0;
	    }
	    else
	    {
		pIO = checkIdxList.Next();
	    }
	}
	if ( idxFound == false )
	{
	    CegoBTreeObject *pBTO = checkBTreeList.First();
	    while ( pBTO && idxFound == false)
	    {
		if ( pBTO->getType() == CegoObject::PBTREE )
		{
		    if ( pBTO->getSchema().Size() == keyList.Size() )
		    {		    
			CegoField *pK = refList.First();
			idxFound = true;
			while ( pK && idxFound )
			{
			    if ( pBTO->getSchema().Find(*pK) )
			    {
				pK = refList.Next();			
			    }
			    else
			    {
				idxFound = false;
			    }		    
			}
		    }
		    
		    // just one primary btree can be found
		    pBTO = 0;
		}
		else
		{
		    pBTO = checkBTreeList.Next();
		}
	    }
	}
	
	if ( idxFound == false )
	    throw Exception(EXLOC, Chain("Primary index or btree not found"));
	  
	CegoTableObject toe;
	getObject(tabSetId, tableName, CegoObject::TABLE, toe);

	ListT<CegoField> schema = toe.getSchema();	

	CegoField *pDF = keyList.First();
	while ( pDF )
	{	
	    CegoField *pF = schema.Find(*pDF);
	    if ( pF == 0 )
	    {
		Chain msg = Chain("Unknown key attribute ") + pDF->getAttrName();
		throw Exception(EXLOC, msg);
	    }
	    pDF = keyList.Next();
	}
		
	pC = getObjectCursor(tabSetId, tableName, tableName, CegoObject::TABLE);
	
	CegoDataPointer dp;

	bool moreTuple = getFirstTuple(pC, schema, dp);
	
	while ( moreTuple && _isAborted == false)
	{	    
	    CegoTableCursor tc(this, tabSetId, refTable);

	    CegoAttrCond ac;
	    
	    CegoField *pDF = keyList.First();
	    while ( pDF )
	    {	
		CegoField *pF = schema.Find(*pDF);
		if ( pF )
		{	   
		    ac.add(CegoAttrComp(pF->getTableAlias(), pF->getAttrName(), EQUAL, pF->getValue())); 
		}
		else
		{
		    Chain msg = Chain("Unknown key attribute ") + pDF->getAttrName();
		    throw Exception(EXLOC, msg);		   
		}
		pDF = keyList.Next();
	    }

	    ListT<CegoField> tfl;
            CegoAttrCond::IndexMatch indexMatch = tc.setup(ac);
 
            if ( indexMatch == CegoAttrCond::FULL || indexMatch == CegoAttrCond::PART )
            {
		tc.getIdxSchema(tfl);
            }
            else
            {
		CegoTableObject oe;
		getObject(tabSetId, refTable, CegoObject::TABLE, oe);
		tfl = oe.getSchema();
            }
 
            CegoDataPointer dp;
 
            bool moreRefTuple = tc.getFirst(tfl, dp);
 
            bool isMatch = false;
            while ( moreRefTuple && ( ! isMatch ) )
            {
                CegoField *pF = tfl.First();
                while ( pF )
                {
                    isMatch = true;
                    CegoField *pD = schema.Find(*pF);
                    if ( pD )
                    {
                        if ( ! ( (CegoFieldValue)pD->getValue() == (CegoFieldValue)pF->getValue()) )
                            isMatch=false;
                    }
                    pF = tfl.Next();
                }
                moreRefTuple = tc.getNext(tfl, dp);
            }
            if ( ! isMatch )
		throw Exception(EXLOC, Chain("Foreign key reference does not exist"));
	    	    
	    moreTuple = getNextTuple(pC, schema, dp);
	}

	if ( _isAborted )
	{	    
	    throw Exception(EXLOC, Chain("Foreign key creation aborted by user"));
	}	    
    }
    catch ( Exception e )
    {
	if ( pC )
	    pC->abort();	
	throw Exception(EXLOC, Chain("Cannot create foreign key"), e);
    }
    
    delete pC;
    
    CegoKeyObject oe(tabSetId, fkey, tableName, keyList, refTable, refList );

    createKeyObject(oe);

    // create log entry
    lr.setObjectInfo(oe.getName(), oe.getType());
    lr.setAction(CegoLogRecord::LOGREC_CREATE);
    
    char *buf;
    buf = (char*)malloc(oe.getEntrySize());

    oe.encode(buf);
    lr.setData(buf);
    lr.setDataLen(oe.getEntrySize());

    _pDBMng->logIt(oe.getTabSetId(), lr, _pLockHandle);
    
    free(buf);
}

void CegoTableManager::createCheck(unsigned tabSetId, const Chain& checkName, const Chain& tableName, CegoPredicate *pPredDesc)
{
    if ( getTID(tabSetId) > 0 )
    {
	Chain msg = Chain("create check in a transaction not allowed"); 
	throw Exception(EXLOC, msg);	
    }

    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));
    
    CegoObjectCursor* pC = 0;
    
    try
    {
	CegoTableObject toe;
	getObject(tabSetId, tableName, CegoObject::TABLE, toe);

	ListT<CegoField> schema = toe.getSchema();	

	// we need to create an additional reference to use the setFieldListArray method
	ListT<CegoField>* xschema[2];
	xschema[0] = &schema;
	xschema[1] = 0;
	
	pC = getObjectCursor(tabSetId, tableName, tableName, CegoObject::TABLE);
	
	CegoDataPointer dp;

	bool moreTuple = getFirstTuple(pC, schema, dp);

	if ( moreTuple )
	{
	    while ( moreTuple && _isAborted == false)
	    {	    		
		pPredDesc->clearAttrCache();
		if ( pPredDesc->eval(0, 0, xschema, 0, 0 ) == false )
		    throw Exception(EXLOC, Chain("Check constraint violated"));
		moreTuple = getNextTuple(pC, schema, dp);
	    }
	}
	else
	{
	    // check attribute match for empty tables
	    CegoExpr *pExpr = pPredDesc->getExpr1();
	    if ( pExpr )
	    {
		ListT<CegoAttrDesc*> adl = pExpr->getAttrRefList();
		CegoAttrDesc **pAD = adl.First();
		while ( pAD )
		{
		    if ( ! schema.Find(CegoField((*pAD)->getTableName(), (*pAD)->getAttrName())))
		    {
			Chain msg = Chain("Unknown attribute " ) + (*pAD)->getAttrName();
			throw Exception(EXLOC, msg);
		    }
		    pAD = adl.Next();
		}
	    }
	    pExpr = pPredDesc->getExpr2();
	    if ( pExpr )
	    {
		ListT<CegoAttrDesc*> adl = pExpr->getAttrRefList();
		CegoAttrDesc **pAD = adl.First();
		while ( pAD )
		{
		    if ( ! schema.Find(CegoField((*pAD)->getTableName(), (*pAD)->getAttrName())))
		    {
			Chain msg = Chain("Unknown attribute " ) + (*pAD)->getAttrName();
			throw Exception(EXLOC, msg);
		    }
		    pAD = adl.Next();
		}
	    }
	    pExpr = pPredDesc->getExpr3();
	    if ( pExpr )
	    {
		ListT<CegoAttrDesc*> adl = pExpr->getAttrRefList();
		CegoAttrDesc **pAD = adl.First();
		while ( pAD )
		{
		    if ( ! schema.Find(CegoField((*pAD)->getTableName(), (*pAD)->getAttrName())))
		    {
			Chain msg = Chain("Unknown attribute " ) + (*pAD)->getAttrName();
			throw Exception(EXLOC, msg);
		    }
		    pAD = adl.Next();
		}
	    }
	}
	if ( _isAborted )
	{	    
	    throw Exception(EXLOC, Chain("Check constraint creation aborted by user"));
	}	
		    
    }
    catch ( Exception e )
    {
	if ( pC )
	    pC->abort();
	
	throw Exception(EXLOC, Chain("Cannot create check"), e);
    }
    
    delete pC;
    
    CegoCheckObject oe(tabSetId, checkName, tableName, pPredDesc );

    createCheckObject(oe);

    // create log entry
    lr.setObjectInfo(oe.getName(), oe.getType());
    lr.setAction(CegoLogRecord::LOGREC_CREATE);
    
    char *buf;
    buf = (char*)malloc(oe.getEntrySize());

    oe.encode(buf);
    lr.setData(buf);
    lr.setDataLen(oe.getEntrySize());

    _pDBMng->logIt(oe.getTabSetId(), lr, _pLockHandle);
    free(buf);    
}

void CegoTableManager::createAlias(unsigned tabSetId, const Chain& aliasName, const Chain& tableName, const ListT<CegoAttrAlias>& aliasList)
{
    if ( aliasName == tableName )
    {
	Chain msg = Chain("Table name and alias name cannot be equal"); 
	throw Exception(EXLOC, msg);		
    }
    
    if ( getTID(tabSetId) > 0 )
    {
	Chain msg = Chain("create check in a transaction not allowed"); 
	throw Exception(EXLOC, msg);	
    }
    
    try
    {
	CegoTableObject toe;
	getObject(tabSetId, tableName, CegoObject::TABLE, toe);
    }
    catch ( Exception e )
    {
	throw Exception(EXLOC, Chain("Cannot create alias"), e);
    }

    CegoAliasObject ao(tabSetId, aliasName, tableName, aliasList);

    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));
    
    createAliasObject(ao);

    // create log entry
    lr.setObjectInfo(ao.getName(), ao.getType());
    lr.setAction(CegoLogRecord::LOGREC_CREATE);
 
    char *buf;
    buf = (char*)malloc(ao.getEntrySize());
    ao.encode(buf);
    lr.setData(buf);
    lr.setDataLen(ao.getEntrySize());

    _pDBMng->logIt(ao.getTabSetId(), lr, _pLockHandle);
    free(buf);
}

void CegoTableManager::createTrigger(unsigned tabSetId, const Chain& triggerName,
				     bool isBefore, bool isOnInsert, bool isOnUpdate, bool isOnDelete,
				     const Chain& tableName, const Chain& triggerText)
{
    if ( getTID(tabSetId) > 0 )
    {
	Chain msg = Chain("create check in a transaction not allowed"); 
	throw Exception(EXLOC, msg);	
    }
    
    try
    {
	CegoTableObject toe;
	getObject(tabSetId, tableName, CegoObject::TABLE, toe);
    }
    catch ( Exception e )
    {
	throw Exception(EXLOC, Chain("Cannot create trigger"), e);
    }

    CegoTriggerObject to(tabSetId, triggerName, isBefore, isOnInsert, isOnUpdate, isOnDelete, tableName, triggerText);

    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));
    
    createTriggerObject(to);

    // create log entry
    lr.setObjectInfo(to.getName(), to.getType());
    lr.setAction(CegoLogRecord::LOGREC_CREATE);
 
    char *buf;
    buf = (char*)malloc(to.getEntrySize());
    to.encode(buf);
    lr.setData(buf);
    lr.setDataLen(to.getEntrySize());

    _pDBMng->logIt(to.getTabSetId(), lr, _pLockHandle);
    free(buf);
}

void CegoTableManager::getPoolInfo(CegoTableObject& oe, ListT< ListT<CegoFieldValue> > &info)
{	
    ListT<CegoField> schema;
    schema.Insert(CegoField(Chain("POOLINFO"), Chain("POOLINFO"), Chain("PARAMETER"),VARCHAR_TYPE, 20)); 
    schema.Insert(CegoField(Chain("POOLINFO"), Chain("POOLINFO"), Chain("VALUE"), VARCHAR_TYPE, 20)); 
    oe = CegoTableObject(0, CegoObject::SYSTEM, Chain("POOLINFO"), schema, Chain("POOLINFO"));
       
    unsigned pageSize;
    unsigned long long totalPages;
    unsigned long long usedPages;
    unsigned long long freePages;
    unsigned long long dirtyPages;
    unsigned long long fixedPages;
    unsigned long long persistentPages;
    unsigned long long noSyncPages;
    unsigned long long numDiskRead;
    unsigned long long numDiskWrite;
    double hitRate;
    double spreadRate;
    unsigned long long readDelay;
    unsigned long long writeDelay;
    unsigned long long curFixCount;
    unsigned long long maxFixCount;
    unsigned long long avgFixTry;
    
    unsigned long long statStart;
    unsigned long long uptime;

    _pDBMng->poolInfo(pageSize, totalPages, usedPages, freePages, dirtyPages, fixedPages, persistentPages, noSyncPages, numDiskRead, numDiskWrite, hitRate, spreadRate, readDelay, writeDelay, curFixCount, maxFixCount, avgFixTry, statStart, uptime);
    
    CegoFieldValue f1a(VARCHAR_TYPE, Chain("Page Size"));
    CegoFieldValue f1b(VARCHAR_TYPE,  Chain(pageSize));
    ListT<CegoFieldValue> fl1;
    fl1.Insert(f1a);
    fl1.Insert(f1b);
    info.Insert(fl1);
    
    CegoFieldValue f2a(VARCHAR_TYPE, Chain("Total Pages"));
    CegoFieldValue f2b(VARCHAR_TYPE,  Chain(totalPages));
    ListT<CegoFieldValue> fl2;
    fl2.Insert(f2a);
    fl2.Insert(f2b);
    info.Insert(fl2);
    
    CegoFieldValue f3a(VARCHAR_TYPE, Chain("Used Pages"));
    CegoFieldValue f3b(VARCHAR_TYPE, Chain(usedPages));
    ListT<CegoFieldValue> fl3;
    fl3.Insert(f3a);
    fl3.Insert(f3b);
    info.Insert(fl3);
    
    CegoFieldValue f4a(VARCHAR_TYPE, Chain("Free Pages"));
    CegoFieldValue f4b(VARCHAR_TYPE, Chain(freePages));
    ListT<CegoFieldValue> fl4;
    fl4.Insert(f4a);
    fl4.Insert(f4b);
    info.Insert(fl4);
    
    CegoFieldValue f5a(VARCHAR_TYPE, Chain("Dirty Pages"));
    CegoFieldValue f5b(VARCHAR_TYPE, Chain(dirtyPages));
    ListT<CegoFieldValue> fl5;
    fl5.Insert(f5a);
    fl5.Insert(f5b);
    info.Insert(fl5);
    
    CegoFieldValue f6a(VARCHAR_TYPE, Chain("Fixed Pages"));
    CegoFieldValue f6b(VARCHAR_TYPE, Chain(fixedPages));
    ListT<CegoFieldValue> fl6;
    fl6.Insert(f6a);
    fl6.Insert(f6b);
    info.Insert(fl6);
    
    CegoFieldValue f7a(VARCHAR_TYPE, Chain("Persistent Pages"));
    CegoFieldValue f7b(VARCHAR_TYPE, Chain(persistentPages));
    ListT<CegoFieldValue> fl7;
    fl7.Insert(f7a);
    fl7.Insert(f7b);
    info.Insert(fl7);
        
    CegoFieldValue f8a(VARCHAR_TYPE, Chain("No Sync Pages"));
    CegoFieldValue f8b(VARCHAR_TYPE, Chain(noSyncPages));
    ListT<CegoFieldValue> fl8;
    fl8.Insert(f8a);
    fl8.Insert(f8b);
    info.Insert(fl8);

    // format spread rate
    Chain srFormated = Chain(spreadRate, "%3.3f");

    CegoFieldValue f9a(VARCHAR_TYPE, Chain("Spread Rate"));
    CegoFieldValue f9b(VARCHAR_TYPE, srFormated);
    ListT<CegoFieldValue> fl9;
    fl9.Insert(f9a);
    fl9.Insert(f9b);
    info.Insert(fl9);
    
    CegoFieldValue f10a(VARCHAR_TYPE, Chain("-------------------"));
    CegoFieldValue f10b(VARCHAR_TYPE, Chain("-------------------"));
    ListT<CegoFieldValue> fl10;
    fl10.Insert(f10a);
    fl10.Insert(f10b);
    info.Insert(fl10);
    
    Datetime dt(statStart);
    CegoFieldValue f11a(VARCHAR_TYPE, Chain("Stat Start"));
    CegoFieldValue f11b(VARCHAR_TYPE, dt.asChain(BUPMNG_STATDTFORMAT));
    ListT<CegoFieldValue> fl11;
    fl11.Insert(f11a);
    fl11.Insert(f11b);
    info.Insert(fl11);

    // format hitrate
    Chain hrFormated = Chain(hitRate, "%3.2f") + Chain("%");

    CegoFieldValue f12a(VARCHAR_TYPE, Chain("Hit Rate"));
    CegoFieldValue f12b(VARCHAR_TYPE, hrFormated);
    ListT<CegoFieldValue> fl12;
    fl12.Insert(f12a);
    fl12.Insert(f12b);
    info.Insert(fl12);

    CegoFieldValue f13a(VARCHAR_TYPE, Chain("Cur Fix Count"));
    CegoFieldValue f13b(VARCHAR_TYPE, curFixCount);
    ListT<CegoFieldValue> fl13;
    fl13.Insert(f13a);
    fl13.Insert(f13b);
    info.Insert(fl13);
    
    CegoFieldValue f14a(VARCHAR_TYPE, Chain("Max Fix Count"));
    CegoFieldValue f14b(VARCHAR_TYPE, maxFixCount);
    ListT<CegoFieldValue> fl14;
    fl14.Insert(f14a);
    fl14.Insert(f14b);
    info.Insert(fl14);
    
    CegoFieldValue f15a(VARCHAR_TYPE, Chain("Avg Fix Try"));
    CegoFieldValue f15b(VARCHAR_TYPE, avgFixTry);
    ListT<CegoFieldValue> fl15;
    fl15.Insert(f15a);
    fl15.Insert(f15b);
    info.Insert(fl15);
    
    CegoFieldValue f16a(VARCHAR_TYPE, Chain("Disk Reads"));
    CegoFieldValue f16b(VARCHAR_TYPE, Chain(numDiskRead));
    ListT<CegoFieldValue> fl16;
    fl16.Insert(f16a);
    fl16.Insert(f16b);
    info.Insert(fl16);
    
    CegoFieldValue f17a(VARCHAR_TYPE, Chain("Disk Writes"));
    CegoFieldValue f17b(VARCHAR_TYPE, Chain(numDiskWrite));
    ListT<CegoFieldValue> fl17;
    fl17.Insert(f17a);
    fl17.Insert(f17b);
    info.Insert(fl17);
    
    unsigned secDelay;
    unsigned msecDelay;
    Chain delayStr;
    Chain fillStr;
    
    secDelay = readDelay / 1000;
    msecDelay = readDelay % 1000;
    fillStr = Chain("000") + Chain(msecDelay);
    delayStr = Chain(secDelay) + Chain(".") + fillStr.subChain(fillStr.length()-3, fillStr.length()) + Chain (" msec");
    
    CegoFieldValue f18a(VARCHAR_TYPE, Chain("Read Delay"));
    CegoFieldValue f18b(VARCHAR_TYPE, Chain(delayStr));
    ListT<CegoFieldValue> fl18;
    fl18.Insert(f18a);
    fl18.Insert(f18b);
    info.Insert(fl18);
    
    secDelay = writeDelay / 1000;
    msecDelay = writeDelay % 1000;
    fillStr = Chain("000") + Chain(msecDelay);
    delayStr = Chain(secDelay) + Chain(".") + fillStr.subChain(fillStr.length()-3, fillStr.length()) + Chain (" msec");
    
    CegoFieldValue f19a(VARCHAR_TYPE, Chain("Write Delay"));
    CegoFieldValue f19b(VARCHAR_TYPE, Chain(delayStr));
    ListT<CegoFieldValue> fl19;
    fl19.Insert(f19a);
    fl19.Insert(f19b);
    info.Insert(fl19);

    CegoFieldValue f20a(VARCHAR_TYPE, Chain("-------------------"));
    CegoFieldValue f20b(VARCHAR_TYPE, Chain("-------------------"));
    ListT<CegoFieldValue> fl20;
    fl20.Insert(f20a);
    fl20.Insert(f20b);
    info.Insert(fl20);
    
    CegoFieldValue f21a(VARCHAR_TYPE, Chain("Pool Uptime"));

    // calculate time string
    unsigned long long d = uptime / ( 3600 * 24 );
    unsigned long long h = ( uptime - ( d * 24 * 3600 )) / 3600;
    unsigned long long m = ( uptime - ( d * 24 * 3600 ) - ( h * 3600) ) / 60;
    unsigned long long s = uptime % 60;
    
    Chain ss = Chain("0") + Chain(s);
    Chain sec = ss.subChain(ss.length()-2,ss.length());

    Chain ms = Chain("0") + Chain(m);
    Chain min = ms.subChain(ms.length()-2,ms.length());
    
    Chain uptimeString = Chain(d) + Chain("d ") + Chain(h) + Chain(":") + min + Chain(":") + sec; 
    CegoFieldValue f21b(VARCHAR_TYPE, uptimeString);
    ListT<CegoFieldValue> fl21;
    fl21.Insert(f21a);
    fl21.Insert(f21b);
    info.Insert(fl21);
}

void CegoTableManager::getSystemInfo(const Chain& tableSet, CegoTableObject& oe, ListT< ListT<CegoFieldValue> > &fa, Chain& format)
{        
    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);
    unsigned tmpFid = _pDBMng->getTmpFid(tableSet);
    
    ListT<CegoField> schema;
    schema.Insert(CegoField(Chain("SYSINFO"), Chain("SYSINFO"), Chain("SPACE"), VARCHAR_TYPE, 10));
    schema.Insert(CegoField(Chain("SYSINFO"), Chain("SYSINFO"), Chain("NUMPAGES"), INT_TYPE, sizeof(int)));
    schema.Insert(CegoField(Chain("SYSINFO"), Chain("SYSINFO"), Chain("USEDPAGES"), INT_TYPE, sizeof(int)));

    oe = CegoTableObject(tabSetId, CegoObject::SYSTEM, Chain("SYSINFO"), schema, Chain("SYSINFO"));

    format = Chain("lrr");
    
    ListT<CegoFieldValue> fv1;

    fv1.Insert(CegoFieldValue(VARCHAR_TYPE, Chain("SYSTEM")));
    fv1.Insert(CegoFieldValue(INT_TYPE, Chain(_pDBMng->getNumPages(tabSetId))));
    fv1.Insert(CegoFieldValue(INT_TYPE, Chain(_pDBMng->getNumUsedPages(tabSetId, _pLockHandle))));

    fa.Insert(fv1);

    ListT<Chain> dfList;
    ListT<unsigned> fidList;
    ListT<unsigned> sizeList;
    
    _pDBMng->getDataFileInfo(tableSet, Chain(XML_SYSFILE_VALUE), dfList, fidList, sizeList);

    Chain *pDF = dfList.First();
    unsigned *pFid = fidList.First();

    while ( pFid && pDF)
    {
	ListT<CegoFieldValue> fv;
		
	fv.Insert(CegoFieldValue(VARCHAR_TYPE, Chain("SYSTEM")));
	fv.Insert(CegoFieldValue(INT_TYPE, Chain(_pDBMng->getNumPages(*pFid))));
	fv.Insert(CegoFieldValue(INT_TYPE, Chain(_pDBMng->getNumUsedPages(*pFid, _pLockHandle))));
	
	fa.Insert(fv);
	
	pFid = fidList.Next();
	pDF = dfList.Next();
    }     
    
    ListT<CegoFieldValue> fv2;
    
    fv2.Insert(CegoFieldValue(VARCHAR_TYPE, Chain("TEMP")));
    fv2.Insert(CegoFieldValue(INT_TYPE, Chain(_pDBMng->getNumPages(tmpFid))));
    fv2.Insert(CegoFieldValue(INT_TYPE,  Chain(_pDBMng->getNumUsedPages(tmpFid, _pLockHandle))));

    fa.Insert(fv2);

    dfList.Empty();
    fidList.Empty();
    sizeList.Empty();

    _pDBMng->getDataFileInfo(tableSet, Chain(XML_TEMPFILE_VALUE), dfList, fidList, sizeList);

    pDF = dfList.First();
    pFid = fidList.First();

    while ( pFid && pDF)
    {
	ListT<CegoFieldValue> fv;
		
	fv.Insert(CegoFieldValue(VARCHAR_TYPE, Chain("TEMP")));
	fv.Insert(CegoFieldValue(INT_TYPE, Chain(_pDBMng->getNumPages(*pFid))));
	fv.Insert(CegoFieldValue(INT_TYPE, Chain(_pDBMng->getNumUsedPages(*pFid, _pLockHandle))));
	
	fa.Insert(fv);
	
	pFid = fidList.Next();
	pDF = dfList.Next();
    }     

    dfList.Empty();
    fidList.Empty();
    sizeList.Empty();

    _pDBMng->getDataFileInfo(tableSet, Chain(XML_APPFILE_VALUE), dfList, fidList, sizeList);

    pDF = dfList.First();
    pFid = fidList.First();

    while ( pFid && pDF)
    {
	ListT<CegoFieldValue> fv;
		
	fv.Insert(CegoFieldValue(VARCHAR_TYPE, Chain("DATAFILE")));
	fv.Insert(CegoFieldValue(INT_TYPE, Chain(_pDBMng->getNumPages(*pFid))));
	fv.Insert(CegoFieldValue(INT_TYPE, Chain(_pDBMng->getNumUsedPages(*pFid, _pLockHandle))));
	
	fa.Insert(fv);
	
	pFid = fidList.Next();
	pDF = dfList.Next();
    }     
}

void CegoTableManager::dumpObject(const Chain& tableSet, const Chain& objName, CegoObject::ObjectType type, Chain& chainDump)
{
    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);
    dumpObject(tabSetId, objName, type, chainDump);
}

void CegoTableManager::dumpObject(unsigned tabSetId, const Chain& objName, CegoObject::ObjectType type, Chain& chainDump)
{
    
    chainDump = Chain("Name: <") + objName + Chain(">\n");
    chainDump += Chain("Type: ");

    switch (type)
    {
    case CegoObject::TABLE:
    case CegoObject::AVLTREE:
    case CegoObject::UAVLTREE:
    case CegoObject::PAVLTREE:
    {       
	chainDump += CegoTypeConverter::getObjectTypeString(type) + Chain("\n");

	CegoTableObject oe;
	getObject(tabSetId, objName, type, oe);

	chainDump += Chain("Schema:\n");
	CegoField* pF = oe.getSchema().First();
	while (pF)
	{	    
	    chainDump += Chain("   TableName: <") + pF->getTableName() + Chain(">\n");
	    chainDump += Chain("   TableAlias: <") + pF->getTableAlias() + Chain(">\n");
	    chainDump += Chain("   AttrName: <") + pF->getAttrName() + Chain(">\n");
	    chainDump += Chain("   Id: <") + Chain(pF->getId()) + Chain(">\n");
	    
	    pF = oe.getSchema().Next();
	}

	CegoObjectCursor* pC = getObjectCursor(tabSetId, oe.getTabName(), objName, type);	

	CegoDataPointer dp;
	unsigned len;
	char* pc = (char*)pC->getFirst(len, dp);

	unsigned long long rowCount=0;
	while ( pc && len > 0 )
	{
	    rowCount++;

	    unsigned long long tid;
	    unsigned long long tastep; 
	    CegoTupleState ts;

	    unsigned toff = CegoQueryHelper::decodeTupleHeader(tid, tastep, ts, pc);

	    char* tp = pc + toff;
	    unsigned tlen = len - toff;

	    chainDump += dp.toChain(); 
	    chainDump += Chain(" Row=") + Chain(rowCount) 
		+ Chain(",Tid=") + Chain(tid)
		+ Chain(",Step=") + Chain(tastep);
	    
	    if ( ts == CegoTupleState::COMMITTED )
		chainDump += Chain(",State=C");
	    else if ( ts == CegoTupleState::INSERTED )
		chainDump += Chain(",State=I");
	    else if ( ts == CegoTupleState::DELETED )
		chainDump += Chain(",State=D");
	    else if ( ts == CegoTupleState::OBSOLETE )
		chainDump += Chain(",State=O");

	    chainDump += Chain(",Data=");
	    
	    if ( type == CegoObject::TABLE )
	    {
		ListT<CegoField> fl = oe.getSchema();
		CegoQueryHelper::decodeFVL(fl, tp, tlen);
		CegoField *pF = fl.First();
		while ( pF )
		{
		    chainDump += Chain("<") + pF->getValue().toChain() + Chain(">");    
		    pF = fl.Next();
		}
		chainDump += Chain("\n");		
	    }
	    else // if ( type == CegoObject::AVLTREE || type == CegoObject::UAVLTREE || type == CegoObject::PAVLTREE )
	    {
		CegoAVLIndexEntry ie;
		ie.setPtr(pc,len);
		
		chainDump += "Entry " + dp.toChain() + ":  Parent=" + ie.getParent().toChain()  + " Left=" + ie.getLeftBranch().toChain() + " Right=" + ie.getRightBranch().toChain() + " Data=" + ie.getData().toChain();
		
		unsigned h = (unsigned)ie.getHeight(); 
		chainDump += " Height=" + Chain(h);

		if ( ie.getIdxPtr() != 0 )
		{
		    unsigned l;
		    memcpy(&l, ie.getIdxPtr(), sizeof(unsigned));
		    chainDump += " Len: " + Chain(l);
		    
		    unsigned v;
		    memcpy(&v, (unsigned*)((long long)ie.getIdxPtr() + sizeof(unsigned)), sizeof(unsigned));
		    chainDump += " Val: " + Chain(v);		   
		}	
		chainDump += "\n";
	    }
	    
	    pc = (char*)pC->getNext(len, dp);
	}
	
	delete pC;

	break;
    }
    case CegoObject::BTREE:
    case CegoObject::PBTREE:
    case CegoObject::UBTREE:
    {
	CegoBTreeObject btoe;
	getObject(tabSetId, objName, type, btoe);
	CegoBTreeManager btreeMng(this, &btoe);
	btreeMng.dumpBTree(chainDump);
	
	break;
    }
    case CegoObject::PROCEDURE:
    case CegoObject::VIEW:
    case CegoObject::ALIAS:
    case CegoObject::TRIGGER:
    case CegoObject::UNDEFINED:
    case CegoObject::SYSTEM:
    case CegoObject::RBSEG:
    case CegoObject::FKEY:
    case CegoObject::CHECK:
    case CegoObject::JOIN:
    {
	chainDump = Chain("Not implemented");
	break;
    }
    }
}

void CegoTableManager::regDataFiles(const Chain& tableSet)
{
    unsigned tmpFileId = _pDBMng->getTmpFid(tableSet); 
    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);
 
    Chain dbTempFileName = _pDBMng->getTmpFileName(tableSet); 
    Chain dbSysFileName = _pDBMng->getSysFileName(tableSet);

    _pDBMng->log(_modId, Logger::NOTICE, Chain("Registering system datafile  ") + dbSysFileName + Chain(" ..."));
    _pDBMng->regDataFile(tabSetId, dbSysFileName, tabSetId, _pLockHandle);

    _pDBMng->log(_modId, Logger::NOTICE, Chain("Registering temp datafile  ") + dbTempFileName + Chain(" ..."));
    _pDBMng->regDataFile(tabSetId, dbTempFileName, tmpFileId, _pLockHandle);

    ListT<Chain> dfList;
    ListT<unsigned> fidList;
    ListT<unsigned> sizeList;
    
    _pDBMng->getDataFileInfo(tableSet, Chain(XML_APPFILE_VALUE), dfList, fidList, sizeList);
	
    Chain *pFileName = dfList.First();
    unsigned *pFid = fidList.First();
    unsigned *pSize = sizeList.First();
    
    while ( pFileName && pFid && pSize ) 
    {	
	_pDBMng->regDataFile(tabSetId, *pFileName, *pFid, _pLockHandle);

	pFileName = dfList.Next();
	pFid = fidList.Next();
	pSize = sizeList.Next();	
    }

    dfList.Empty();
    fidList.Empty();
    sizeList.Empty();

    _pDBMng->getDataFileInfo(tableSet, Chain(XML_SYSFILE_VALUE), dfList, fidList, sizeList);
	
    pFileName = dfList.First();
    pFid = fidList.First();
    pSize = sizeList.First();
    
    while ( pFileName && pFid && pSize ) 
    {
	_pDBMng->regDataFile(tabSetId, *pFileName, *pFid, _pLockHandle);

	pFileName = dfList.Next();
	pFid = fidList.Next();
	pSize = sizeList.Next();	
    }

    dfList.Empty();
    fidList.Empty();
    sizeList.Empty();

    _pDBMng->getDataFileInfo(tableSet, Chain(XML_TEMPFILE_VALUE), dfList, fidList, sizeList);
	
    pFileName = dfList.First();
    pFid = fidList.First();
    pSize = sizeList.First();
    
    while ( pFileName && pFid && pSize ) 
    {
	_pDBMng->regDataFile(tabSetId, *pFileName, *pFid, _pLockHandle);

	pFileName = dfList.Next();
	pFid = fidList.Next();
	pSize = sizeList.Next();	
    }

    dfList.Empty();
    fidList.Empty();
    sizeList.Empty();
    
    if ( _pDBMng->checkPointDumpEnabled(tabSetId) )
    {
	_pDBMng->restoreCheckpointDump(tabSetId, _pLockHandle);
    }

    _pDBMng->log(_modId, Logger::NOTICE, Chain("Registration finished"));
}

///////////////////////
// protected methods //
///////////////////////

void CegoTableManager::resetTemp(const Chain& tableSet)
{
    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);
    unsigned tmpFileId = _pDBMng->getTmpFid(tableSet);
    
    _pDBMng->resetDataFile(tmpFileId);

    PageIdType pageOffset = _pDBMng->getTempPageOffset(tabSetId);
    
    for ( PageIdType i = 0 ; i < TABMNG_HASHSIZE ; i++ )
    {
	_pDBMng->claimPage(pageOffset + i, _pLockHandle);		
    }

    ListT<Chain> dfList;
    ListT<unsigned> fidList;
    ListT<unsigned> sizeList;
        
    _pDBMng->getDataFileInfo(tableSet, Chain(XML_TEMPFILE_VALUE), dfList, fidList, sizeList);
    	
    Chain *pFileName = dfList.First();
    unsigned *pFid = fidList.First();
    unsigned *pSize = sizeList.First();
    
    while ( pFileName && pFid && pSize ) 
    {
	_pDBMng->resetDataFile(*pFid);
	pFileName = dfList.Next();
	pFid = fidList.Next();
	pSize = sizeList.Next();	
    }
}

void CegoTableManager::finishOpenTransaction(unsigned tabSetId)
{		     
    // ensure that no transaction is active, in case of a crash recovery, this might be
    _tid[tabSetId] = 0;
    _tastep[tabSetId] = 0;
    
    _pTM->finishOpenTransaction(tabSetId);
}	

void CegoTableManager::extractIndexValue(const ListT<CegoField>& tableSchema, const ListT<CegoField>& indexSchema, char* p, unsigned len, unsigned& idxLen)
{
    CegoField* pIF = indexSchema.First();
           	
    idxLen = 0;

    while (pIF)
    {   
	CegoField* pTF = tableSchema.First();	

	while (pTF)
	{	    
	    if ( (Chain)pTF->getAttrName() == (Chain)pIF->getAttrName() )
	    {
		unsigned flen = pTF->getValue().getLength();
		
		idxLen += flen + sizeof(unsigned);
		if ( idxLen > len)
		{
		    throw Exception(EXLOC, Chain("Index value too long")); 
		}
   
		memcpy(p, &flen, sizeof(unsigned));
		p += sizeof(unsigned);
		if ( flen > 0 )
		{
		    memcpy(p, pTF->getValue().getValue(), flen);
		    p += flen;
		}	
	    }
	    pTF = tableSchema.Next();
	}

	pIF = indexSchema.Next();
    }   
}

void CegoTableManager::abort()
{
    _isAborted = true;
}

void CegoTableManager::proceed()
{
    _isAborted = false;
}

bool CegoTableManager::isAborted() const
{
    return _isAborted;
}

void CegoTableManager::poolP()
{
    if ( _pPool )
    {
	_pPool->P(_thrIdx);
    }
}

void CegoTableManager::poolV()
{
    if ( _pPool )
    {
	_pPool->V(_thrIdx);
    }
}

void CegoTableManager::addCompProcedure(unsigned tabSetId, CegoProcedure *pProc)
{
    poolP();

    try
    {
	CegoProcedure** pCheckProc = _procList[tabSetId].First();
	while ( pCheckProc )
	{
	    if ( (Chain)(*pCheckProc)->getName() == (Chain)pProc->getName() )
	    {
		throw Exception(EXLOC, Chain("Procedure ") + pProc->getName() + Chain(" already exists"));  
	    }
	    pCheckProc = _procList[tabSetId].Next();
	}
	
	_procList[tabSetId].Insert(pProc);

	poolV();
    }
    catch ( Exception e )
    {
	poolV();
	throw Exception(EXLOC, Chain("Cannot add compiled procedure"), e);
    }    
}

void CegoTableManager::removeCompProcedure(unsigned tabSetId, const Chain& procName)
{
    poolP();

    CegoProcedure** pProc = _procList[tabSetId].First();
    while ( pProc )
    {
	if ( (Chain)(*pProc)->getName() == (Chain)procName )
	{	   
	    CegoProcedure *pDelProc = *pProc;

	    delete pDelProc;

	    _procList[tabSetId].Remove(*pProc);

	    poolV();
	    return;
	}
	pProc = _procList[tabSetId].Next();
    }

    poolV();

    return;
}

bool CegoTableManager::checkCompProcedure(unsigned tabSetId, const Chain& procName)
{
    poolP();

    CegoProcedure** pProc = _procList[tabSetId].First();
    while ( pProc )
    {
	if ( (Chain)(*pProc)->getName() == (Chain)procName )
	{
	    poolV();
	    return true;
	}
	pProc = _procList[tabSetId].Next();
    }
    poolV();
    return false;
}

CegoProcedure* CegoTableManager::getCompProcedure(unsigned tabSetId, const Chain& procName)
{
    poolP();
    CegoProcedure** pProc = _procList[tabSetId].First();
    while ( pProc )
    {
	if ( (Chain)(*pProc)->getName() == (Chain)procName )
	{
	    poolV();
	    return *pProc;
	}
	pProc = _procList[tabSetId].Next();
    }

    poolV();
    Chain msg = Chain("Procedure ") + procName + Chain(" not compiled"); 
    throw Exception(EXLOC, msg);
}

void CegoTableManager::addCompView(unsigned tabSetId, CegoView *pView)
{
    poolP();
    _viewList[tabSetId].Insert(pView);
    poolV();
}

void CegoTableManager::removeCompView(unsigned tabSetId, const Chain& viewName)
{
    poolP();
    CegoView** pView = _viewList[tabSetId].First();
    while ( pView )
    {
	if ( (Chain)(*pView)->getViewName() == (Chain)viewName )
	{
	    CegoView *pDelView = *pView;
	    delete pDelView;
	    
	    _viewList[tabSetId].Remove(*pView);

	    poolV();

	    return;
	}
	pView = _viewList[tabSetId].Next();
    }
    poolV();
    return;
}

bool CegoTableManager::checkCompView(unsigned tabSetId, const Chain& viewName)
{
    poolP();
    CegoView** pView = _viewList[tabSetId].First();
    while ( pView )
    {
	if ( (Chain)(*pView)->getViewName() == (Chain)viewName )
	{
	    poolV();
	    return true;
	}
	pView = _viewList[tabSetId].Next();
    }
    poolV();
    return false;
}

CegoView* CegoTableManager::getCompView(unsigned tabSetId, const Chain& viewName)
{
    poolP();
    CegoView** pView = _viewList[tabSetId].First();
    while ( pView )
    {
	if ( (Chain)(*pView)->getViewName() == (Chain)viewName )
	{
	    poolV();
	    return *pView;
	}
	pView = _viewList[tabSetId].Next();
    }
    poolV();

    Chain msg = Chain("View ") + viewName + Chain(" not compiled"); 
    throw Exception(EXLOC, msg);
}

void CegoTableManager::addCompTrigger(unsigned tabSetId, CegoTrigger *pTrigger)
{
    poolP();
    _triggerList[tabSetId].Insert(pTrigger);
    poolV();
}

void CegoTableManager::removeCompTrigger(unsigned tabSetId, const Chain& triggerName)
{
    poolP();
    CegoTrigger** pTrigger = _triggerList[tabSetId].First();
    while ( pTrigger )
    {
	if ( (Chain)(*pTrigger)->getName() == (Chain)triggerName )
	{
	    CegoTrigger* pDelTrigger = *pTrigger;
	    delete pDelTrigger;
	    
	    _triggerList[tabSetId].Remove(*pTrigger);

	    poolV();

	    return;
	}
	pTrigger = _triggerList[tabSetId].Next();
    }
    poolV();
    return;
}

bool CegoTableManager::checkCompTrigger(unsigned tabSetId, const Chain& triggerName)
{
    poolP();
    CegoTrigger** pTrigger = _triggerList[tabSetId].First();
    while ( pTrigger )
    {
	if ( (Chain)(*pTrigger)->getName() == (Chain)triggerName )
	{
	    poolV();
	    return true;
	}
	pTrigger = _triggerList[tabSetId].Next();
    }
    poolV();
    return false;
}

CegoTrigger* CegoTableManager::getCompTrigger(unsigned tabSetId, const Chain& triggerName)
{
    poolP();
    CegoTrigger** pTrigger = _triggerList[tabSetId].First();
    while ( pTrigger )
    {
	if ( (Chain)(*pTrigger)->getName() == (Chain)triggerName )
	{
	    poolV();
	    return *pTrigger;
	}
	pTrigger = _triggerList[tabSetId].Next();
    }
    poolV();

    Chain msg = Chain("Trigger ") + triggerName + Chain(" not compiled"); 
    throw Exception(EXLOC, msg);
}

void CegoTableManager::removeAllComp(unsigned tabSetId)
{
    poolP();

    CegoView** pView = _viewList[tabSetId].First();
    while ( pView )
    {
	Chain viewName = (*pView)->getViewName();
	
	_pDBMng->useObject(tabSetId, viewName, CegoObject::VIEW, CegoDatabaseManager::EXCLUSIVE_WRITE, this);
	CegoView *pDelView = *pView;

	// we first have to delete
	delete pDelView;

	// then we can release from the list
	_viewList[tabSetId].Remove(*pView);

	_pDBMng->unuseObject(tabSetId, viewName, CegoObject::VIEW);
	
	pView = _viewList[tabSetId].First();
    }
    
    CegoProcedure** pProc = _procList[tabSetId].First();
    while ( pProc )
    {
	Chain procName = (*pProc)->getName();

	_pDBMng->useObject(tabSetId, procName, CegoObject::PROCEDURE, CegoDatabaseManager::EXCLUSIVE_WRITE, this);

	CegoProcedure *pDelProc = *pProc;

	// we first have to delete
	delete pDelProc;

	// the we can remove from the list
	_procList[tabSetId].Remove(*pProc);

	_pDBMng->unuseObject(tabSetId, procName, CegoObject::PROCEDURE);
	
	pProc = _procList[tabSetId].First();
    }

    CegoTrigger** pTrigger = _triggerList[tabSetId].First();
    while ( pTrigger )
    {
	Chain triggerName = (*pTrigger)->getName();
	
	_pDBMng->useObject(tabSetId, triggerName, CegoObject::TRIGGER, CegoDatabaseManager::EXCLUSIVE_WRITE, this);
		
	CegoTrigger *pDelTrigger = *pTrigger;

	// we first have to delete
	delete pDelTrigger;

	// then we can release from the list
	_triggerList[tabSetId].Remove(*pTrigger);

	_pDBMng->unuseObject(tabSetId, triggerName, CegoObject::TRIGGER);
		
	pTrigger = _triggerList[tabSetId].First();
    }

    poolV();
}

void CegoTableManager::getLHLockStat(unsigned long long lockId, Chain& lockName, unsigned& lockCount, unsigned long long &numRdLock, unsigned long long &numWrLock, unsigned long long &sumRdDelay, unsigned long long &sumWrDelay)
{
    _pLockHandle->getLockStat(lockId, lockName, lockCount, numRdLock, numWrLock, sumRdDelay, sumWrDelay);
}

void CegoTableManager::getLHAggLockStat(const Chain& lockName, unsigned& numLock, unsigned& lockCount, unsigned long long &numRdLock, unsigned long long &numWrLock, unsigned long long &sumRdDelay, unsigned long long &sumWrDelay)
{
    _pLockHandle->getAggLockStat(lockName, numLock, lockCount, numRdLock, numWrLock, sumRdDelay, sumWrDelay);
}

CegoTransactionManager* CegoTableManager::getTransactionManager()
{
    return _pTM;
} 

void CegoTableManager::increaseBlobRef(unsigned tabSetId, PageIdType pageId)
{
    CegoBufferPage bp;
    _pDBMng->bufferFix(bp, tabSetId, pageId, CegoBufferPool::SYNC, _pLockHandle);

    unsigned long long blobRef;

    memcpy (&blobRef, bp.getChunkEntry(), sizeof(unsigned long long));
    blobRef++;
    memcpy (bp.getChunkEntry(), &blobRef, sizeof(unsigned long long));
    _pDBMng->bufferUnfix(bp, true, _pLockHandle);
}

void CegoTableManager::decreaseBlobRef(unsigned tabSetId, PageIdType pageId)
{
    CegoBufferPage bp;
    _pDBMng->bufferFix(bp, tabSetId, pageId, CegoBufferPool::SYNC, _pLockHandle);
    
    unsigned long long blobRef;
    memcpy (&blobRef, bp.getChunkEntry(), sizeof(unsigned long long));

    if ( blobRef <= 1 )
    {
	while ( bp.isFixed() )
	{      
	    pageId = bp.getNextPageId();
	    
	    _pDBMng->bufferRelease(bp, _pLockHandle);
	    
	    if ( pageId )
		_pDBMng->bufferFix(bp, tabSetId, pageId, CegoBufferPool::SYNC, _pLockHandle);
	}
    }
    else
    {
	blobRef--;
	memcpy (bp.getChunkEntry(), &blobRef, sizeof(unsigned long long));
	_pDBMng->bufferUnfix(bp, true, _pLockHandle);
    }
}

void CegoTableManager::increaseClobRef(unsigned tabSetId, PageIdType pageId)
{
    CegoBufferPage bp;
    _pDBMng->bufferFix(bp, tabSetId, pageId, CegoBufferPool::SYNC, _pLockHandle);

    unsigned long long clobRef;

    memcpy (&clobRef, bp.getChunkEntry(), sizeof(unsigned long long));
    clobRef++;
    memcpy (bp.getChunkEntry(), &clobRef, sizeof(unsigned long long));
    _pDBMng->bufferUnfix(bp, true, _pLockHandle);
}

void CegoTableManager::decreaseClobRef(unsigned tabSetId, PageIdType pageId)
{
    CegoBufferPage bp;
    _pDBMng->bufferFix(bp, tabSetId, pageId, CegoBufferPool::SYNC, _pLockHandle);
    
    unsigned long long clobRef;
    memcpy (&clobRef, bp.getChunkEntry(), sizeof(unsigned long long));

    if ( clobRef <= 1 )
    {
	while ( bp.isFixed() )
	{      
	    pageId = bp.getNextPageId();
	    
	    _pDBMng->bufferRelease(bp, _pLockHandle);
	    
	    if ( pageId )
		_pDBMng->bufferFix(bp, tabSetId, pageId, CegoBufferPool::SYNC, _pLockHandle);
	}
    }
    else
    {
	clobRef--;
	memcpy (bp.getChunkEntry(), &clobRef, sizeof(unsigned long long));
	_pDBMng->bufferUnfix(bp, true, _pLockHandle);
    }
}
    
unsigned char* CegoTableManager::getBlobData(unsigned tabSetId, PageIdType pageId, unsigned long long& blobSize)
{
    CegoBufferPage bp;
    try
    {
	_pDBMng->bufferFix(bp, tabSetId, pageId, CegoBufferPool::SYNC, _pLockHandle);

	unsigned long long blobRef;
	memcpy (&blobRef, bp.getChunkEntry(), sizeof(unsigned long long));

	memcpy (&blobSize, (char*)(bp.getChunkEntry() + sizeof(unsigned long long)), sizeof(unsigned long long));
	
	// allocate buffer of size blobsize

	unsigned char* rawBuf = (unsigned char*)malloc(blobSize);
	if (rawBuf == NULL)
	{
	    Chain msg = Chain("Cannot allocate blob data of ") + Chain(blobSize + 1) + Chain(" bytes");
	    throw Exception(EXLOC, msg);
	}
		
	unsigned char* rawPtr = rawBuf;

	unsigned long long writtenByte = 0;
	
	while ( bp.isFixed() )
	{	    
	    unsigned chunkSize;

	    // first page with written clob size, so we have to sub the size bytes
            if ( writtenByte == 0 )
            {
                // take the full page chunk ?
                if (  bp.getChunkLen() - 2 * sizeof(unsigned long long ) < blobSize  )
                {
		    chunkSize = bp.getChunkLen() - 2 * sizeof(unsigned long long);
                }
                else // just take the needed chunk
                {
		    chunkSize = blobSize;
                }
            }
            else // just take the needed
            {
                // take the full page chunk ?
                if (  bp.getChunkLen() < (unsigned)(blobSize - writtenByte)  )
                {
		    chunkSize = bp.getChunkLen();
                }
                else // just take the needed chunk
                {
		    chunkSize = blobSize - writtenByte;
                }
            }
	    
	    char* src = 0;
	    if ( writtenByte == 0 )
	    {
		src = (char*)(bp.getChunkEntry() + 2 * sizeof(unsigned long long));
	    }
	    else
	    {
		src = (char*)(bp.getChunkEntry());
	    }
	    memcpy(rawPtr, src, chunkSize);
	    
	    rawPtr += chunkSize;
	    writtenByte += chunkSize;

	    pageId = bp.getNextPageId();
	    
	    _pDBMng->bufferUnfix(bp, false, _pLockHandle);
	    
	    if ( pageId )			
		_pDBMng->bufferFix(bp, tabSetId, pageId, CegoBufferPool::SYNC, _pLockHandle);	    
	}
	return rawBuf;     	
    }
    catch ( Exception e )
    {
	if ( bp.isFixed() )
	    _pDBMng->bufferUnfix(bp, true, _pLockHandle);
	throw Exception(EXLOC, Chain("Cannot get blob data"), e);
    }
    return 0;       
}

char* CegoTableManager::getClobData(unsigned tabSetId, PageIdType pageId, unsigned long long& clobSize)
{
    CegoBufferPage bp;
    try
    {
	_pDBMng->bufferFix(bp, tabSetId, pageId, CegoBufferPool::SYNC, _pLockHandle);

	unsigned long long clobRef;
	memcpy (&clobRef, bp.getChunkEntry(), sizeof(unsigned long long));
	
	memcpy (&clobSize, (char*)(bp.getChunkEntry() + sizeof(unsigned long long)), sizeof(unsigned long long));
	
	// allocate buffer of size clobsize
	
	char* rawBuf = (char*)malloc(clobSize + 1);
	if (rawBuf == NULL)
	{
	    Chain msg = Chain("Cannot allocate clob data of ") + Chain(clobSize + 1) + Chain(" bytes");
	    throw Exception(EXLOC, msg);
	}
		
	char* rawPtr = rawBuf;

	unsigned long long writtenByte = 0;
	
	while ( bp.isFixed() )
	{	    
	    unsigned chunkSize;

	    // first page with written clob size, so we have to sub the size bytes
            if ( writtenByte == 0 )
            {
                // take the full page chunk ?
                if (  bp.getChunkLen() - 2 * sizeof(unsigned long long ) < clobSize  )
                {
		    chunkSize = bp.getChunkLen() - 2 * sizeof(unsigned long long);
                }
                else // just take the needed chunk
                {
		    chunkSize = clobSize;
                }
            }
            else // just take the needed
            {
                // take the full page chunk ?
                if (  bp.getChunkLen() < (unsigned)(clobSize - writtenByte)  )
                {
		    chunkSize = bp.getChunkLen();
                }
                else // just take the needed chunk
                {
		    chunkSize = clobSize - writtenByte;
                }
            }
	    
	    char* src = 0;
	    if ( writtenByte == 0 )
	    {
		src = (char*)(bp.getChunkEntry() + 2 * sizeof(unsigned long long));
	    }
	    else
	    {
		src = (char*)(bp.getChunkEntry());

	    }
	    memcpy(rawPtr, src, chunkSize);
	    
	    rawPtr += chunkSize;
	    writtenByte += chunkSize;

	    pageId = bp.getNextPageId();
	    
	    _pDBMng->bufferUnfix(bp, false, _pLockHandle);
	    
	    if (  pageId )			
		_pDBMng->bufferFix(bp, tabSetId, pageId, CegoBufferPool::SYNC, _pLockHandle);	    
	}
	// ensure termination character
	rawBuf[clobSize]=0;
	return rawBuf;
    }
    catch ( Exception e )
    {
	if ( bp.isFixed() )
	    _pDBMng->bufferUnfix(bp, true, _pLockHandle);
	throw Exception(EXLOC, Chain("Cannot get clob data"), e);
    }
    return 0;
}

void CegoTableManager::putBlobData(unsigned tabSetId, unsigned char* data, unsigned long long blobSize, PageIdType& pageId)
{
    CegoBufferPage bp;

    try
    {
	getNewFilePage(bp, tabSetId, CegoObject::TABLE, false, true);
	bp.initPage(CegoBufferPage::BLOB);
	
	pageId = bp.getPageId();
				
	unsigned freeInPage = bp.getChunkLen();
	char* pagePtr = bp.getChunkEntry();
	
	unsigned long long blobRef = 0;
	memcpy(pagePtr, &blobRef, sizeof(unsigned long long));
	pagePtr += sizeof(unsigned long long);
	freeInPage -= sizeof(unsigned long long);
	
	memcpy(pagePtr, &blobSize, sizeof(unsigned long long));
	pagePtr += sizeof(unsigned long long);
	freeInPage -= sizeof(unsigned long long);
	
	unsigned char *bufPtr = 0; 
	unsigned long long availFromBuf = 0;
		
	unsigned long long writtenByte = 0;
	while ( writtenByte < blobSize )
	{		    
	    if ( availFromBuf == 0 )		    
	    {		
		availFromBuf=blobSize;	       
		bufPtr = data;	     
	    }        
	    if ( freeInPage == 0 )
	    {
		CegoBufferPage nextPage;
		getNewFilePage(nextPage, tabSetId, CegoObject::TABLE, false, true);
		nextPage.initPage(CegoBufferPage::BLOB);
		
		bp.setNextPageId(nextPage.getPageId());
		
		_pDBMng->bufferUnfix(bp, true, _pLockHandle);
		
		bp = nextPage;
		
		freeInPage = bp.getChunkLen();
		pagePtr = bp.getChunkEntry();
	    }
		    
	    if ( freeInPage >= (unsigned)availFromBuf )
	    {
		memcpy(pagePtr, bufPtr, availFromBuf);
		writtenByte += availFromBuf;
		pagePtr += availFromBuf;
		freeInPage -= availFromBuf;
		availFromBuf = 0;
	    }
	    else if ( freeInPage < (unsigned)availFromBuf )
	    {
		memcpy(pagePtr, bufPtr, freeInPage);
		writtenByte += freeInPage;
		bufPtr += freeInPage;
		availFromBuf -= freeInPage;
		freeInPage = 0;
	    }	    
	}
	_pDBMng->bufferUnfix(bp, true, _pLockHandle);
    }
    catch ( Exception e )
    {
	if ( bp.isFixed() )
	    _pDBMng->bufferUnfix(bp, true, _pLockHandle);
	throw Exception(EXLOC, Chain("Cannot put blob data"), e);
    }
}

void CegoTableManager::putClobData(unsigned tabSetId, char* data, unsigned long long clobSize, PageIdType& pageId)
{    
    CegoBufferPage bp;

    try
    {
	getNewFilePage(bp, tabSetId, CegoObject::TABLE, false, true);
	bp.initPage(CegoBufferPage::CLOB);
	
	pageId = bp.getPageId();
	
	unsigned freeInPage = bp.getChunkLen();
	char* pagePtr = bp.getChunkEntry();
	
	unsigned long long clobRef = 0;
	memcpy(pagePtr, &clobRef, sizeof(unsigned long long));
	pagePtr += sizeof(unsigned long long);
	freeInPage -= sizeof(unsigned long long);

	memcpy(pagePtr, &clobSize, sizeof(unsigned long long));
	pagePtr += sizeof(unsigned long long);
	freeInPage -= sizeof(unsigned long long);
	
	char *bufPtr = 0; 
	unsigned long long availFromBuf = 0;
		
	unsigned long long writtenByte = 0;
	while ( writtenByte < clobSize )
	{		    
	    if ( availFromBuf == 0 )		    
	    {		
		availFromBuf=clobSize;	       
		bufPtr = data;	     
	    }        
	    if ( freeInPage == 0 )
	    {
		CegoBufferPage nextPage;
		getNewFilePage(nextPage, tabSetId, CegoObject::TABLE, false, true);
		nextPage.initPage(CegoBufferPage::CLOB);
		
		bp.setNextPageId(nextPage.getPageId());
		
		_pDBMng->bufferUnfix(bp, true, _pLockHandle);
		
		bp = nextPage;
		
		freeInPage = bp.getChunkLen();
		pagePtr = bp.getChunkEntry();
	    }
		    
	    if ( freeInPage >= (unsigned)availFromBuf )
	    {
		memcpy(pagePtr, bufPtr, availFromBuf);
		writtenByte += availFromBuf;
		pagePtr += availFromBuf;
		freeInPage -= availFromBuf;
		availFromBuf = 0;
	    }
	    else if ( freeInPage < (unsigned)availFromBuf )
	    {
		memcpy(pagePtr, bufPtr, freeInPage);
		writtenByte += freeInPage;
		bufPtr += freeInPage;
		availFromBuf -= freeInPage;
		freeInPage = 0;
	    }
	}
	_pDBMng->bufferUnfix(bp, true, _pLockHandle);
    }
    catch ( Exception e )
    {
	if ( bp.isFixed() )
	    _pDBMng->bufferUnfix(bp, true, _pLockHandle);
	throw Exception(EXLOC, Chain("Cannot put clob data"), e);
    }
}

void CegoTableManager::getBlobs(unsigned tabSetId, const ListT<CegoField>& fvl, ListT<CegoBlob>& blobList)
{
    CegoField* pF = fvl.First();
    while (pF)
    {
	if ( pF->getValue().getType() == BLOB_TYPE  )
	{
	    PageIdType pageId;
	    memcpy(&pageId, pF->getValue().getValue(), sizeof(PageIdType));
	    
	    unsigned long long blobSize;
	    unsigned char* blobBuf = getBlobData(tabSetId, pageId, blobSize);

	    blobList.Insert(CegoBlob(pageId, blobBuf, blobSize));
	}
	pF = fvl.Next();
    }
}

void CegoTableManager::getClobs(unsigned tabSetId, const ListT<CegoField>& fvl, ListT<CegoClob>& clobList)
{    
    CegoField* pF = fvl.First();
    while (pF)
    {
	if ( pF->getValue().getType() == CLOB_TYPE  )
	{
	    PageIdType pageId;
	    memcpy(&pageId, pF->getValue().getValue(), sizeof(PageIdType));
	    
	    unsigned long long clobSize;
	    char* clobBuf = getClobData(tabSetId, pageId, clobSize);
	    
	    clobList.Insert(CegoClob(pageId, clobBuf, clobSize));	    
	}
	pF = fvl.Next();
    }
}

void CegoTableManager::getBlobs(unsigned tabSetId, ListT<CegoExpr*>& exprList, CegoProcBlock* pBlock, ListT<CegoBlob>& blobList )
{
    CegoExpr** pExpr = exprList.First();
    while ( pExpr )
    {
	// (*pExpr)->setBlock(pBlock);
	    
	CegoFieldValue fv;
	
	if ( (*pExpr)->checkLob(fv, pBlock) )
	{
	    if ( fv.getType() == BLOB_TYPE )
	    {
		PageIdType pageId;
		memcpy(&pageId, fv.getValue(), sizeof(PageIdType));
		
		unsigned long long blobSize;
		unsigned char* blobBuf = getBlobData(tabSetId, pageId, blobSize);
		
		blobList.Insert(CegoBlob(pageId, blobBuf, blobSize));	    
	    }
	}
	pExpr = exprList.Next();
    }
}

void CegoTableManager::getClobs(unsigned tabSetId, ListT<CegoExpr*>& exprList, CegoProcBlock* pBlock, ListT<CegoClob>& clobList)
{
    CegoExpr** pExpr = exprList.First();
    while ( pExpr )
    {
	// (*pExpr)->setBlock(pBlock);
		    
	CegoFieldValue fv;
	if ( (*pExpr)->checkLob(fv, pBlock)  )
	{
	    if ( fv.getType() == CLOB_TYPE)
	    {
		PageIdType pageId;
		memcpy(&pageId, fv.getValue(), sizeof(PageIdType));
		
		unsigned long long clobSize;
		char* clobBuf = getClobData(tabSetId, pageId, clobSize);
		
		clobList.Insert(CegoClob(pageId, clobBuf, clobSize));
	    }
	}
	pExpr = exprList.Next();
    }
}

void CegoTableManager::addBUStat(unsigned tabSetId, const Chain& butype, const Chain& msg)
{
    // insert entry in bustat table

    CegoTableObject boe;
    getObject(tabSetId, Chain(SYSTAB_BUSTAT_ID), CegoObject::SYSTEM, boe);
    ListT<CegoField> fvl = boe.getSchema();
    CegoField *pF = fvl.First();
    while ( pF )
    {
	if (pF->getAttrName() == Chain(SYSTAB_TS_ATTR) )
	{
	    Datetime n;
	    unsigned long long *pDV = new (unsigned long long);    
	    *pDV = n.asLong();    
	    CegoFieldValue fv(DATETIME_TYPE, pDV, sizeof(unsigned long long), true);
	    pF->setValue(fv);
	}
	else if ( pF->getAttrName() == Chain(SYSTAB_BUINFO_ATTR) )
	{
	    pF->setValue(CegoFieldValue(VARCHAR_TYPE, butype));	
	}
	else if ( pF->getAttrName() == Chain(SYSTAB_BUMSG_ATTR) )
	{
	    pF->setValue(CegoFieldValue(VARCHAR_TYPE, msg));	
	}
	pF = fvl.Next();
    }
    
    CegoDataPointer bp;
    insertDataTable(boe, fvl, bp, true, true);
}

bool CegoTableManager::typeConversionAllowed(CegoDataType fromType, CegoDataType toType)
{    
    if ( fromType == toType 
	 || ( fromType == INT_TYPE && toType == LONG_TYPE )
	 || ( fromType == INT_TYPE && toType == VARCHAR_TYPE )
	 || ( fromType == INT_TYPE && toType == BOOL_TYPE )
	 || ( fromType == INT_TYPE && toType == DATETIME_TYPE )
	 || ( fromType == INT_TYPE && toType == BIGINT_TYPE )
	 || ( fromType == INT_TYPE && toType == FLOAT_TYPE )
	 || ( fromType == INT_TYPE && toType == DOUBLE_TYPE )
	 || ( fromType == INT_TYPE && toType == DECIMAL_TYPE )
	 || ( fromType == LONG_TYPE && toType == VARCHAR_TYPE )
	 || ( fromType == LONG_TYPE && toType == BOOL_TYPE )
	 || ( fromType == LONG_TYPE && toType == BIGINT_TYPE )
	 || ( fromType == LONG_TYPE && toType == DOUBLE_TYPE )
	 || ( fromType == LONG_TYPE && toType == DECIMAL_TYPE )
	 || ( fromType == BOOL_TYPE && toType == INT_TYPE )
	 || ( fromType == BOOL_TYPE && toType == LONG_TYPE )
	 || ( fromType == BOOL_TYPE && toType == VARCHAR_TYPE )
	 || ( fromType == BOOL_TYPE && toType == BIGINT_TYPE )
	 || ( fromType == BOOL_TYPE && toType == FLOAT_TYPE )
	 || ( fromType == BOOL_TYPE && toType == DOUBLE_TYPE )
	 || ( fromType == BOOL_TYPE && toType == DECIMAL_TYPE )
	 || ( fromType == DATETIME_TYPE && toType == INT_TYPE )
	 || ( fromType == DATETIME_TYPE && toType == VARCHAR_TYPE )
	 || ( fromType == DATETIME_TYPE && toType == BIGINT_TYPE )
	 || ( fromType == DATETIME_TYPE && toType == FLOAT_TYPE )
	 || ( fromType == DATETIME_TYPE && toType == DOUBLE_TYPE )
	 || ( fromType == DATETIME_TYPE && toType == DECIMAL_TYPE )	 
	 || ( fromType == BIGINT_TYPE && toType == VARCHAR_TYPE )	 
	 || ( fromType == FLOAT_TYPE && toType == VARCHAR_TYPE )	 
	 || ( fromType == DOUBLE_TYPE && toType == VARCHAR_TYPE )	 
	 || ( fromType == DECIMAL_TYPE && toType == VARCHAR_TYPE )
	 || ( fromType == SMALLINT_TYPE && toType == VARCHAR_TYPE )	 
	 || ( fromType == TINYINT_TYPE && toType == VARCHAR_TYPE )
	 || ( fromType == TINYINT_TYPE && toType == INT_TYPE )
	 || ( fromType == TINYINT_TYPE && toType == LONG_TYPE )	)
    {
	return true;
    }
    
    return false;
}
