///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoQueryManager.cc
// -------------------
// Cego query manager class implementation
//                                                         
// Design and Implementation by Bjoern Lemke               
//
// (C)opyright 2000-2026 Bjoern Lemke
//
// IMPLEMENTATION MODULE
//
// Class: CegoQueryManager
//
// Description: Query manager for high level data access
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

// LFC INCLUDES
#include <lfcbase/Exception.h>

// CEGO INCLUDES
#include "CegoQueryManager.h"
#include "CegoAVLIndexCursor.h"
#include "CegoAVLIndexManager.h"
#include "CegoBTreeManager.h"
#include "CegoXMLdef.h"
#include "CegoTypeConverter.h"
#include "CegoRecoveryManager.h"
#include "CegoAction.h"
#include "CegoCheckpointDump.h"

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

CegoQueryManager::ActiveTSUser::ActiveTSUser()
{
}
 
CegoQueryManager::ActiveTSUser::ActiveTSUser(const Chain& tableSet)
{
    _tableSet = tableSet;
}

CegoQueryManager::ActiveTSUser::ActiveTSUser (const Chain& tableSet, const Chain& userName, const Chain& passwd)
{
    _tableSet = tableSet;
    _userName = userName;
    _passwd = passwd;    
}

CegoQueryManager::ActiveTSUser::~ActiveTSUser()
{
}
	
const Chain& CegoQueryManager::ActiveTSUser::getUserName() const
{
    return _userName;
}

const Chain& CegoQueryManager::ActiveTSUser::getPasswd() const
{
    return _passwd;
}

CegoQueryManager::ActiveTSUser& CegoQueryManager::ActiveTSUser::operator = (const ActiveTSUser& u)
{
    _tableSet = u._tableSet;
    _userName = u._userName;
    _passwd = u._passwd;
    return (*this);   
}

bool CegoQueryManager::ActiveTSUser::operator == (const CegoQueryManager::ActiveTSUser& u) const
{
    if ( _tableSet == u._tableSet)
	return true;
    return false;
}

CegoQueryManager::CegoQueryManager(CegoDatabaseManager *pDBMng) : CegoTableManager(pDBMng)
{
    _modId = pDBMng->getModId("CegoQueryManager");
    _pRepHash = new HashT<CegoReplacer>(REPLACER_MAXNUM, REPLACER_HASHRANGE);
    _authEnabled = true;
    _numAllocated = 0;
    _threadId = 0;
    _pPA = 0; 
}

CegoQueryManager::~CegoQueryManager()
{
    if ( _pPA )
	delete _pPA;

    if ( _pRepHash )
    {
	CegoReplacer *pRep = _pRepHash->First();
	while ( pRep )
	{
	    pRep->clean();
	    pRep = _pRepHash->Next();
	}
	if ( _pRepHash )
	    delete _pRepHash;
    }
}

void CegoQueryManager::createTableSet(const Chain& tableSet)
{
    createBasicTableSet(tableSet);

    startQueryTableSet(tableSet, false, false, false);
    
    _pDBMng->log(_modId, Logger::NOTICE, Chain("Creating system space ..."));
    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);
    createSystemSpace(tabSetId);

    stopTableSet(tableSet, false);    
}


void CegoQueryManager::registerObjects(const Chain& tableSet)
{
    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);
    
    ListT<Chain> tabList;
    getObjectList(tabSetId, CegoObject::TABLE, tabList);

    Chain *pTableName = tabList.First();
    while ( pTableName )
    {	
#ifdef CGDEBUG
	_pDBMng->log(_modId, Logger::DEBUG, Chain("Adding table ") + *pTableName + Chain(" to tableset ") + tableSet);
#endif
	_pDBMng->addObject(tabSetId, *pTableName, CegoObject::TABLE);
	pTableName = tabList.Next();
    }

    ListT<Chain> viewList;
    getObjectList(tabSetId, CegoObject::VIEW, viewList);
    Chain *pViewName = viewList.First();
    while ( pViewName )
    {	
#ifdef CGDEBUG
	_pDBMng->log(_modId, Logger::DEBUG, Chain("Adding view ") + *pViewName + Chain(" to tableset ") + tableSet);
#endif
	_pDBMng->addObject(tabSetId, *pViewName, CegoObject::VIEW);
	pViewName = viewList.Next();
    }
    
    ListT<Chain> idxList;
    getObjectList(tabSetId, CegoObject::AVLTREE, idxList);
    Chain *pIdxName = idxList.First();
    while ( pIdxName )
    {	
#ifdef CGDEBUG
	_pDBMng->log(_modId, Logger::DEBUG, Chain("Adding index ") + *pIdxName + Chain(" to tableset ") + tableSet);
#endif
	_pDBMng->addObject(tabSetId, *pIdxName, CegoObject::AVLTREE);
	pIdxName = idxList.Next();
    }

    ListT<Chain> btreeList;
    getObjectList(tabSetId, CegoObject::BTREE, btreeList);
    Chain *pBTreeName = btreeList.First();
    while ( pBTreeName )
    {	
#ifdef CGDEBUG
	_pDBMng->log(_modId, Logger::DEBUG, Chain("Adding btree ") + *pBTreeName + Chain(" to tableset ") + tableSet);
#endif
	_pDBMng->addObject(tabSetId, *pBTreeName, CegoObject::BTREE);
	pBTreeName = btreeList.Next();
    }

    ListT<Chain> procList;
    getObjectList(tabSetId, CegoObject::PROCEDURE, procList);
    Chain *pProcName = procList.First();
    while ( pProcName )
    {
#ifdef CGDEBUG
	_pDBMng->log(_modId, Logger::DEBUG, Chain("Adding procedure ") + *pProcName + Chain(" to tableset ") + tableSet);
#endif
	_pDBMng->addObject(tabSetId, *pProcName, CegoObject::PROCEDURE);
	pProcName = procList.Next();
    }

    ListT<Chain> fkeyList;
    getObjectList(tabSetId, CegoObject::FKEY, fkeyList);
    Chain *pFKey = fkeyList.First();
    while ( pFKey )
    {	
#ifdef CGDEBUG
	_pDBMng->log(_modId, Logger::DEBUG, Chain("Adding foreign key ") + *pFKey + Chain(" to tableset ") + tableSet);
#endif
	_pDBMng->addObject(tabSetId, *pFKey, CegoObject::FKEY);
	pFKey = fkeyList.Next();
    }

    ListT<Chain> checkList;
    getObjectList(tabSetId, CegoObject::CHECK, checkList);
    Chain *pCheck = checkList.First();
    while ( pCheck )
    {	
#ifdef CGDEBUG
	_pDBMng->log(_modId, Logger::DEBUG, Chain("Adding check ") + *pCheck + Chain(" to tableset ") + tableSet);
#endif
	_pDBMng->addObject(tabSetId, *pCheck, CegoObject::CHECK);
	pCheck = checkList.Next();
    }

    ListT<Chain> triggerList;
    getObjectList(tabSetId, CegoObject::TRIGGER, triggerList);
    Chain *pTrigger = triggerList.First();
    while ( pTrigger )
    {	
#ifdef CGDEBUG
	_pDBMng->log(_modId, Logger::DEBUG, Chain("Adding trigger ") + *pTrigger + Chain(" to tableset ") + tableSet);
#endif
	_pDBMng->addObject(tabSetId, *pTrigger, CegoObject::TRIGGER);
	pTrigger = triggerList.Next();
    }

    ListT<Chain> aliasList;
    getObjectList(tabSetId, CegoObject::ALIAS, aliasList);
    Chain *pAlias = aliasList.First();
    while ( pAlias )
    {
#ifdef CGDEBUG
	_pDBMng->log(_modId, Logger::DEBUG, Chain("Adding alias ") + *pAlias + Chain(" to tableset ") + tableSet);
#endif
	_pDBMng->addObject(tabSetId, *pAlias, CegoObject::ALIAS);
	pAlias = aliasList.Next();
    }
}

void CegoQueryManager::stopQueryTableSet(const Chain& tableSet, bool archComplete)
{    
    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);
    
    _pDBMng->removeAllObjects(tabSetId);
    _pDBMng->releaseTableCache(tableSet);
    _pDBMng->releaseQueryCache(tableSet);

    stopTableSet(tableSet, archComplete);
}

void CegoQueryManager::startQueryTableSet(const Chain& tableSet, bool cleanIt, bool cpDump, bool doTempReset)
{
    
    Chain runState = _pDBMng->getTableSetRunState(tableSet);
    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);
    
    if ( runState == Chain(XML_CHECKPOINT_VALUE) )
    {
	///////////////////////////////////////
	// checkpoint dump restore procedure //
	///////////////////////////////////////
	
	if ( _pDBMng->checkPointDumpEnabled(tabSetId) )
	{

	    _pDBMng->log(_modId, Logger::NOTICE, Chain("Restoring checkpoint dump ..."));
	    Chain tsRoot = _pDBMng->getTSRoot(tableSet);
	    unsigned pageSize = _pDBMng->getPageSize();
	    
	    CegoCheckpointDump cpd(tableSet, tsRoot, pageSize);
	    if ( cpd.readyDumpExists() == false )
	    {
		cpd.commitDump();
	    }
	}
	else
	{
	    throw Exception(EXLOC, Chain("Checkpoint crash detected, tableset might be inconsistent"));
	}
    }

    if ( runState == Chain(XML_INCOMPLETE_VALUE) )
    {
	throw Exception(EXLOC, Chain("Incomplete tableset status detected, manual recovery needed")); 	
    }

    if ( runState == Chain(XML_ONLINE_VALUE) )
    {
	throw Exception(EXLOC, Chain("Tableset already online")); 	
    }
    
    _pDBMng->log(_modId, Logger::NOTICE, Chain("Starting tableset ") + tableSet + Chain(" ..."));
    
    _pDBMng->setCheckPointDump(tableSet, cpDump);
    
    Chain tsTicketName = _pDBMng->getTSTicket(tableSet);

    Chain correctMode = _pDBMng->getAutoCorrect(tableSet);
    
    File tsTicket(tsTicketName);
    if ( tsTicket.exists()) 
	throw Exception(EXLOC, Chain("Backup tableset ticket exists"));
    
    regDataFiles(tableSet);
    
    // we assume recovery mode during first startup phase
    _pDBMng->setTableSetRunState(tableSet, XML_RECOVERY_VALUE);

    // set active log file
    _pDBMng->setActiveLogFile(tableSet);
    
    // get max written lsn
    unsigned long long maxLogLSN = _pDBMng->getMaxLSN(tabSetId);
    
    registerObjects(tableSet);
    
    // get checkpoint lsn
    long cplsn = _pDBMng->getCommittedLSN(tableSet);
    
    _pDBMng->setCurrentLSN(tabSetId, cplsn);
    
    if ( cplsn == maxLogLSN ||  maxLogLSN == 0  )
    {
	_pDBMng->log(_modId, Logger::NOTICE, Chain("Tableset ") + tableSet + Chain(" in sync at lsn=") + Chain(cplsn) + Chain(", no recovery required"));
	finishOpenTransaction(tabSetId);
    }
    else if ( cplsn < maxLogLSN )
    {	
	_pDBMng->log(_modId, Logger::NOTICE, Chain("Tableset ") + tableSet + Chain(" not in sync, recovery required ( Commited lsn=") + Chain(cplsn) + Chain(")"));
	
	unsigned long long lsn;
	long long ts = 0;
	
	_pDBMng->log(_modId, Logger::NOTICE, Chain("Starting recovery ... "));    
	
	setIgnoreInvalid(true);
	
	try
	{	    
	    CegoRecoveryManager recoveryMng(this);

	    if ( correctMode == Chain(XML_DIRECT_VALUE) )
		recoveryMng.prepareForCrashRecovery(tabSetId, true);
	    else
		recoveryMng.prepareForCrashRecovery(tabSetId, false);
	    
	    recoveryMng.recoverCurrentTransactionLog(tabSetId, 0, 0, lsn, ts);
	    
	    // increase lsn to next
	    _pDBMng->setCurrentLSN(tabSetId, lsn);
	    
	    _pDBMng->log(_modId, Logger::NOTICE, Chain("Recovery finished"));    
	    
	    _pDBMng->log(_modId, Logger::NOTICE, Chain("Closing open transactions ... "));    
	    finishOpenTransaction(tabSetId);
	    _pDBMng->log(_modId, Logger::NOTICE, Chain("Transactions closed"));    
	    
	    setIgnoreInvalid(false);
	    
	}
	catch ( Exception e)
	{
	    _pDBMng->setTableSetRunState(tableSet, XML_OFFLINE_VALUE);
	    throw Exception(EXLOC, Chain("Cannot start tableset ") + tableSet, e);
	}
    }
    else
    {
	throw Exception(EXLOC, "Checkpoint lsn is too high ( max log lsn = " + Chain(maxLogLSN) + ", lsn=" + Chain(cplsn) + Chain(")")); 
    }
    
    // do autocorrect here
    
    if ( correctMode == Chain(XML_DIRECT_VALUE) || correctMode == Chain(XML_POST_VALUE) )
    {	    	   
	try
	{	
	    _pDBMng->log(_modId, Logger::NOTICE, Chain("Perform autocorrect for tableset ") + tableSet + Chain(" ..."));		    
	    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);
	    correctTableSet(tabSetId, false);	  
	}
	catch ( Exception e)
	{
	    // _pDBMng->log(_modId, Logger::LOGERR, msg);
	    stopTableSet(tableSet, false);
	    throw Exception(EXLOC, Chain("Cannot correct tableset ") + tableSet, e);
	}
    }
	
    if ( doTempReset )
    {
	_pDBMng->log(_modId, Logger::NOTICE, Chain("Resetting temp space for tableset ") + tableSet + Chain(" ..."));
	resetTemp(tableSet);
    }
    
    if ( cleanIt )
    {
	_pDBMng->log(_modId, Logger::NOTICE, Chain("Cleaning tableset ") + tableSet + Chain(" ..."));
	unsigned cleanCount = cleanTableSet(tabSetId);
	_pDBMng->log(_modId, Logger::NOTICE, Chain(cleanCount) + Chain(" pages cleaned"));
    }

    // now starting log
    _pDBMng->log(_modId, Logger::NOTICE, Chain("Starting log for tableset ") + tableSet + Chain(" ..."));
    _pDBMng->startLog(tabSetId);
    
    _pDBMng->setTableSetRunState(tableSet, XML_ONLINE_VALUE); 

    // finally, we write a checkpoint with log switch ( must be done after startLog )
    _pDBMng->writeCheckPoint(tableSet, true, false, _pLockHandle);
    
    _pDBMng->allocateTableCache(tableSet);
    _pDBMng->allocateQueryCache(tableSet);
    
}

void CegoQueryManager::getQueryObject(const Chain& tableSet, const Chain& objName, CegoObject::ObjectType type, CegoDecodableObject& oe)
{
    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);

    if ( _authEnabled == true && _pDBMng->verifyAccess(tabSetId, objName, type, CegoXMLSpace::READ, _authUser) == false )
    {
	Chain msg = Chain("Access not allowed for object ") + objName;
	throw Exception(EXLOC, msg); 
    }

#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Getting object ") + objName + Chain(" of type ") + CegoTypeConverter::getObjectTypeString(type));
#endif

    // getLocalObject(tabSetId, objName, type, oe);
    
    getObject(tabSetId, objName, type, oe);
    oe.setLocal(true);
    oe.setTableSet(tableSet);
}

void CegoQueryManager::truncateQueryTable(const Chain& tableName, const Chain& tableSet)
{
#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Truncating table ") + tableName);
#endif

    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);
    
    if ( _authEnabled == true && _pDBMng->verifyAccess(tabSetId, tableName, CegoObject::TABLE, CegoXMLSpace::MODIFY, _authUser) == false )
    {
	Chain msg = Chain("Access not allowed for table ") + tableName;
	throw Exception(EXLOC, msg); 
    }

    truncateTable(tabSetId, tableName);
    _pDBMng->cleanCache(tabSetId, CegoObject::TABLE, tableName);	
}

void CegoQueryManager::dropQueryObject(const Chain& objName, const Chain& tableSet, CegoObject::ObjectType type)
{
#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Dropping object ") + objName);
#endif

    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);

    if ( _authEnabled == true && _pDBMng->verifyAccess(tabSetId, objName, type, CegoXMLSpace::MODIFY, _authUser) == false )
    {
	Chain msg = Chain("Access not allowed for object ") + objName;
	throw Exception(EXLOC, msg); 
    }

    dropObjectSynced(tabSetId, objName, type);
    
    if ( type == CegoObject::TABLE || type == CegoObject::VIEW || type == CegoObject::PROCEDURE )
    {
	_pDBMng->cleanCache(tabSetId, type, objName);
    }
}

void CegoQueryManager::createQueryTable(const Chain& tableSet, const Chain& tableName, ListT<CegoField>& fldList, ListT<CegoField>& idxList, bool useColumnId)
{
#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Creating global table ") + tableName + Chain(" in tableset ") + tableSet);
#endif

    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);

    if ( _authEnabled == true && _pDBMng->verifyAccess(tabSetId, tableName, CegoObject::TABLE, CegoXMLSpace::MODIFY, _authUser) == false )
    {
	Chain msg = Chain("Access not allowed for object ") + tableName;
	throw Exception(EXLOC, msg); 
    }

    createDataTable(tabSetId, tableName, CegoObject::TABLE, fldList, useColumnId);
    _pDBMng->addObject(tabSetId, tableName, CegoObject::TABLE);
    
    if ( ! idxList.isEmpty() )
    {
	Chain idxName = tableName + Chain(TABMNG_PBTREE_SUFFIX);
	
	try
	{	    
	    createPrimaryIndexTable(tabSetId, idxName, tableName, idxList);
	}
	catch ( Exception e )
	{	    
	    removeObject(tabSetId, tableName, CegoObject::TABLE);
	    _pDBMng->removeObject(tabSetId, tableName, CegoObject::TABLE);
	    throw Exception(EXLOC, Chain("Cannot create primary index table"), e);
	}
	_pDBMng->addObject(tabSetId, idxName, CegoObject::BTREE);
    }

}

void CegoQueryManager::createQueryIndex( const Chain& tableSet, const Chain& indexName, const Chain& tableName, ListT<CegoField>& idxList, CegoObject::ObjectType type, bool isCached)
{
#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Creating global index ") + indexName + Chain(" in tableset ") + tableSet);
#endif

    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);

    if ( _authEnabled == true && _pDBMng->verifyAccess(tabSetId, indexName, CegoObject::AVLTREE, CegoXMLSpace::MODIFY, _authUser) == false )
    {
	Chain msg = Chain("Access not allowed for index ") + indexName;
	throw Exception(EXLOC, msg); 
    }
    
    createIndexTableSynced(tabSetId, indexName, tableName, type, idxList, isCached);
}

void CegoQueryManager::createQueryForeignKey( const Chain& tableSet, const Chain& fkey, const Chain& tableName, const ListT<CegoField>& keyList, const Chain& refTable, const ListT<CegoField>& refList)
{
#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Creating global foreign key ") + fkey + Chain(" in tableset ") + tableSet);
#endif

    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);

    if ( _authEnabled == true && _pDBMng->verifyAccess(tabSetId, tableName, CegoObject::TABLE, CegoXMLSpace::MODIFY, _authUser) == false )
    {
	Chain msg = Chain("Access not allowed for object ") + tableName;
	throw Exception(EXLOC, msg); 
    }

    createForeignKey(tabSetId, fkey, tableName, keyList, refTable, refList);
    _pDBMng->addObject(tabSetId, fkey, CegoObject::FKEY);
}


void CegoQueryManager::createQueryCheck( const Chain& tableSet, const Chain& checkName, const Chain& tableName, CegoPredicate *pPredDesc)
{
#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Creating global check ") + checkName + Chain(" in tableset ") + tableSet);
#endif
    
    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);

    if ( _authEnabled == true && _pDBMng->verifyAccess(tabSetId, tableName, CegoObject::TABLE, CegoXMLSpace::MODIFY, _authUser) == false )
    {
	Chain msg = Chain("Access not allowed for object ") + tableName;
	throw Exception(EXLOC, msg); 
    }

    createCheck(tabSetId, checkName, tableName, pPredDesc);    
    _pDBMng->addObject(tabSetId, checkName, CegoObject::CHECK);
}

/*
void CegoDistManager::createLocalCheck(unsigned tabSetId, const Chain& checkName, const Chain& tableName, CegoPredicate *pPredDesc)
{
    createCheck(tabSetId, checkName, tableName, pPredDesc);    
    _pDBMng->addObject(tabSetId, checkName, CegoObject::CHECK);
}
*/

void CegoQueryManager::reorgQueryObject(const Chain& tableSet, const Chain& objName, CegoObject::ObjectType type)
{
#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Reorg global object ") + objName + Chain(" in tableset ") + tableSet);
#endif

    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);

    if ( _authEnabled == true && _pDBMng->verifyAccess(tabSetId, objName, type, CegoXMLSpace::MODIFY, _authUser) == false )
    {
	Chain msg = Chain("Access not allowed for object ") + objName;
	throw Exception(EXLOC, msg); 
    }

    reorgObjectSynced(tabSetId, objName, type);	
}

void CegoQueryManager::startTransaction( const Chain& tableSet)
{
#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Starting global transaction in tableset ") + tableSet);
#endif

    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);

    beginTransaction(tabSetId, true);
}

long CegoQueryManager::endTransaction( const Chain& tableSet)
{
#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Ending global transaction in tableset ") + tableSet);
#endif
    
    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);
    return commitTransactionSynced(tabSetId);  
}

long CegoQueryManager::rollbackTransaction(const Chain& tableSet)
{
#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Rollbacking global transaction in tableset ") + tableSet);
#endif

    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);

    return rollbackTransactionSynced(tabSetId);
}

unsigned long long CegoQueryManager::getTid( const Chain& tableSet)
{
    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);

    return getTID(tabSetId);
    
    
}

void CegoQueryManager::setAllocatedSortArea(unsigned long long n)
{
    _numAllocated = n;
}

unsigned long long CegoQueryManager::getAllocatedSortArea() const
{
    return _numAllocated;
}


void CegoQueryManager::insertQueryTable(CegoTableObject& oe, ListT<CegoField>& fvl)
{    

    if ( _authEnabled == true && _pDBMng->verifyAccess(oe.getTabSetId(), oe.getName(), oe.getType(), CegoXMLSpace::WRITE, _authUser) == false )
    {
	Chain msg = Chain("Access not allowed for object ") + oe.getName();
	throw Exception(EXLOC, msg); 
    }

    _pDBMng->useObject(oe.getTabSetId(), oe.getName(), oe.getType(), CegoDatabaseManager::SHARED,  this);
    
    try
    {
	ListT<CegoTableObject> idxList;
	ListT<CegoBTreeObject> btreeList;
	ListT<CegoKeyObject> keyList;
	ListT<CegoCheckObject> checkList;
	ListT<CegoTriggerObject> triggerList;
	ListT<CegoAliasObject> aliasList;
	unsigned numInvalid;
	
	bool doAppend;
	bool doLogging = true;
	
	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;
	}

	CegoTriggerObject *pTO = triggerList.First();
	while ( pTO )
	{
	    if ( pTO->isOnInsert() && pTO->isBefore() )
	    {
		CegoTrigger *pTrigger = getTrigger(pTO->getTabSetId(), pTO->getName());
		pTrigger->execute(&fvl);		
	    }
	    pTO = triggerList.Next();
	}
	
	CegoDataPointer sysEntry;
	Chain virginIndex;
	CegoDataPointer dp;
	insertDataTable(oe, fvl, idxList, btreeList, keyList, checkList, sysEntry, virginIndex, dp, doLogging, doAppend, true, true);
	
	pTO = triggerList.First();
	while ( pTO )
	{
	    if ( pTO->isOnInsert() && pTO->isBefore() == false )
	    {
		CegoTrigger *pTrigger = getTrigger(pTO->getTabSetId(), pTO->getName());
		pTrigger->execute(&fvl);		
	    }
	    pTO = triggerList.Next();
	}
    }
    catch ( Exception e )
    {
	_pDBMng->unuseObject(oe.getTabSetId(), oe.getName(), oe.getType());
	throw Exception(EXLOC, Chain("Cannot insert data"), e);
    }
    _pDBMng->unuseObject(oe.getTabSetId(), oe.getName(), oe.getType());
}

void CegoQueryManager::insertQueryTable(CegoTableObject& oe, ListT< ListT<CegoField> >& fva )
{    

    if ( _authEnabled == true && _pDBMng->verifyAccess(oe.getTabSetId(), oe.getName(), oe.getType(), CegoXMLSpace::WRITE, _authUser) == false )
    {
	Chain msg = Chain("Access not allowed for object ") + oe.getName();
	throw Exception(EXLOC, msg); 
    }

    _pDBMng->useObject(oe.getTabSetId(), oe.getName(), oe.getType(), CegoDatabaseManager::SHARED,  this);
    
    try
    {		
	ListT<CegoTableObject> idxList;
	ListT<CegoBTreeObject> btreeList;
	ListT<CegoKeyObject> keyList;
	ListT<CegoCheckObject> checkList;
	ListT<CegoTriggerObject> triggerList;
	ListT<CegoAliasObject> aliasList;
	unsigned numInvalid;
	
	bool doAppend;
	bool doLogging = true;
	
	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;
	}

	ListT<CegoField> *pFVL = fva.First();
	unsigned numEntry = fva.Size();
	unsigned entryCount=0;
	
	while ( pFVL )
	{
	    entryCount++;
		    
	    CegoTriggerObject *pTO = triggerList.First();
	    while ( pTO )
	    {
		if ( pTO->isOnInsert() && pTO->isBefore() )
		{
		    CegoTrigger *pTrigger = getTrigger(pTO->getTabSetId(), pTO->getName());
		    pTrigger->execute(pFVL);		
		}
		pTO = triggerList.Next();
	    }
	    
	    CegoDataPointer sysEntry;
	    Chain virginIndex;
	    CegoDataPointer dp;

	    // for performance reasons, just for last insert call, we do flush log ( entryCount == numEntry )
	    insertDataTable(oe, *pFVL, idxList, btreeList, keyList, checkList, sysEntry, virginIndex, dp, doLogging, doAppend, true, entryCount == numEntry);
	    
	    pTO = triggerList.First();
	    while ( pTO )
	    {
		if ( pTO->isOnInsert() && pTO->isBefore() == false )
		{
		    CegoTrigger *pTrigger = getTrigger(pTO->getTabSetId(), pTO->getName());
		    pTrigger->execute(pFVL);		
		}
		pTO = triggerList.Next();
	    }

	    pFVL = fva.Next();
	}
    }
    catch ( Exception e )
    {
	_pDBMng->unuseObject(oe.getTabSetId(), oe.getName(), oe.getType());
	throw Exception(EXLOC, Chain("Cannot insert data"), e);
    }
    _pDBMng->unuseObject(oe.getTabSetId(), oe.getName(), oe.getType());
}

unsigned long long CegoQueryManager::deleteQueryTable(CegoTableObject& oe, CegoPredicate* pPred, CegoProcBlock* pBlock)
{

    if ( _authEnabled == true && _pDBMng->verifyAccess(oe.getTabSetId(), oe.getName(), oe.getType(), CegoXMLSpace::WRITE, _authUser) == false )
    {
	Chain msg = Chain("Access not allowed for object ") + oe.getName();
	throw Exception(EXLOC, msg); 
    }

    unsigned long long delCount = 0;    
    
    bool forceTransaction=false;
    if ( getTID(oe.getTabSetId()) == 0 )
    {
	forceTransaction=true;
	beginTransaction(oe.getTabSetId(), true);
    }
    
    _pDBMng->useObject(oe.getTabSetId(), oe.getName(), oe.getType(), CegoDatabaseManager::SHARED, this);
    
    try
    {		
	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"));
	}

	CegoTriggerObject *pTO = triggerList.First();
	while ( pTO )
	{
	    if ( pTO->isOnDelete() && pTO->isBefore() )
	    {
		CegoTrigger *pTrigger = getTrigger(pTO->getTabSetId(), pTO->getName());
		pTrigger->execute();		
	    }
	    pTO = triggerList.Next();
	}
	
	delCount = deleteDataTable(oe, idxList, btreeList, keyList, pPred, pBlock, true);

	pTO = triggerList.First();
	while ( pTO )
	{
	    if ( pTO->isOnDelete() && pTO->isBefore() == false )
	    {
		CegoTrigger *pTrigger = getTrigger(pTO->getTabSetId(), pTO->getName());
		pTrigger->execute();		
	    }
	    pTO = triggerList.Next();
	}	
    }
    catch ( Exception e)
    {	
	_pDBMng->unuseObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE);

	if ( forceTransaction )
	{    	    
	    _pDBMng->useObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE, CegoDatabaseManager::SHARED, this);

	    try
	    {
		rollbackTableTransaction(oe.getTabSetId(), true);
	    }
	    catch ( Exception e )
	    {
		_pDBMng->unuseObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE);
		throw Exception(EXLOC, Chain("Cannot rollback transaction"), e);
	    }
	    _pDBMng->unuseObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE);
	}

	throw Exception(EXLOC, Chain("Cannot delete data"), e);	
    }

    _pDBMng->unuseObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE);
    
    if ( forceTransaction )
    {
	_pDBMng->useObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE_WRITE, this);
	
	try
	{
	    // for the commit, we have to use the table object in exclusive mode
	    commitTableTransaction(oe.getTabSetId(), true);
	}
	catch ( Exception e )
	{
	    _pDBMng->unuseObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE);
	    throw Exception(EXLOC, Chain("Cannot commit transaction"), e);
	}

	_pDBMng->unuseObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE);
    }

    return delCount;
}

unsigned long long CegoQueryManager::updateQueryTable(CegoTableObject& oe,  
						 CegoPredicate* pPred, 
						 ListT<CegoField>& updList, 
						 ListT<CegoExpr*>& exprList,
						 bool returnOnFirst,
						 ListT<CegoField>& returnList, 
						 CegoProcBlock* pBlock)
{
    
    if ( _authEnabled == true && _pDBMng->verifyAccess(oe.getTabSetId(), oe.getName(), oe.getType(), CegoXMLSpace::WRITE, _authUser) == false )
    {
	Chain msg = Chain("Access not allowed for object ") + oe.getName();
	throw Exception(EXLOC, msg); 
    }

    unsigned long long updCount = 0;
    bool forceTransaction=false;
    if ( getTID(oe.getTabSetId()) == 0 )
    {
	forceTransaction=true;
	beginTransaction(oe.getTabSetId(), true);
    }

    _pDBMng->useObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE, CegoDatabaseManager::SHARED, this);
    
    try
    {
	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 update operations"));    
	}

	CegoTriggerObject *pTO = triggerList.First();
	while ( pTO )
	{
	    if ( pTO->isOnUpdate() && pTO->isBefore() )
	    {
		CegoTrigger *pTrigger = getTrigger(pTO->getTabSetId(), pTO->getName());

		ListT<CegoField> tupdList = updList;
		CegoField* pF = tupdList.First();
		CegoExpr** pExpr = exprList.First();
		while ( pF )
		{
		    CegoFieldValue fv = (*pExpr)->evalFieldValue(0, 0);
		    pF->setValue(fv);		    
		    pF = tupdList.Next();
		    pExpr = exprList.Next();
		}
		pTrigger->execute(&tupdList);
		
	    }
	    pTO = triggerList.Next();
	}
	
	updCount = updateDataTable(oe.getTabSetId(), oe.getTabName(), oe.getTabAlias(),
				   idxList, btreeList, keyList, checkList,
				   pPred, updList, exprList, returnOnFirst, returnList, pBlock);

	pTO = triggerList.First();
	while ( pTO )
	{
	    if ( pTO->isOnUpdate() && pTO->isBefore() == false )
	    {
		CegoTrigger *pTrigger = getTrigger(pTO->getTabSetId(), pTO->getName());

		ListT<CegoField> tupdList = updList;
		CegoField* pF = tupdList.First();
		CegoExpr** pExpr = exprList.First();
		while ( pF )
		{
		    CegoFieldValue fv = (*pExpr)->evalFieldValue(0, 0);
		    pF->setValue(fv);		    
		    pF = tupdList.Next();
		    pExpr = exprList.Next();
		}
		pTrigger->execute(&tupdList);
		
	    }
	    pTO = triggerList.Next();
	}
    }
    catch ( Exception e )
    {
	_pDBMng->unuseObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE);

	if ( forceTransaction )
	{    	    
	    _pDBMng->useObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE, CegoDatabaseManager::SHARED, this);
   
	    try
	    {
		rollbackTableTransaction(oe.getTabSetId(), true);
	    }
	    catch ( Exception e )
	    {
		_pDBMng->unuseObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE);
		throw Exception(EXLOC, Chain("Cannot rollback transaction"), e);
	    }
	}

	_pDBMng->unuseObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE);
	throw Exception(EXLOC, Chain("Cannot update data"), e);	
    }

    _pDBMng->unuseObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE);
    
    if ( forceTransaction )
    {
	_pDBMng->useObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE_WRITE, this);
	
	try
	{
	    // for the commit, we have to use the table object in exclusive mode
	    commitTableTransaction(oe.getTabSetId(), true);
	}
	catch ( Exception e )
	{	    
	    _pDBMng->unuseObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE);
	    throw Exception(EXLOC, Chain("Cannot commit transaction"), e);
	}
	_pDBMng->unuseObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE);
    }

    return updCount;
}

void CegoQueryManager::alterQueryTable(CegoTableObject& oe, const ListT<CegoAlterDesc>& alterList)
{
#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Altering global table ") + oe.getName());
#endif

    if ( _authEnabled == true && _pDBMng->verifyAccess(oe.getTabSetId(), oe.getName(), oe.getType(), CegoXMLSpace::MODIFY, _authUser) == false )
    {
	Chain msg = Chain("Access not allowed for object ") + oe.getName();
	throw Exception(EXLOC, msg); 
    }

    alterDataTableSynced(oe, alterList);
}

void CegoQueryManager::renameQueryObject(const Chain& tableSet, const Chain& objName, CegoObject::ObjectType type,  const Chain& newObjName)
{
#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Renaming global table ") + objName);
#endif

    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);

    if ( _authEnabled == true && _pDBMng->verifyAccess(tabSetId, objName, type, CegoXMLSpace::MODIFY, _authUser) == false )
    {
	Chain msg = Chain("Access not allowed for object ") + objName;
	throw Exception(EXLOC, msg); 
    }
    
    if ( objectExists(tabSetId, newObjName, type) )
    {
	Chain msg = Chain("Object ") +  newObjName + Chain(" already exists");
	throw Exception(EXLOC, msg);
    }
    
    _pDBMng->removeObject(tabSetId, objName, type);
    renameObject(tabSetId, objName, type, newObjName);
    _pDBMng->addObject(tabSetId, newObjName, type);

}

void CegoQueryManager::createQueryView(const Chain& tableSet, const Chain& viewName, const ListT<CegoField>& schema, const Chain& viewText)
{
#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Creating global view ") + viewName + Chain(" in tableset ") + tableSet);
#endif

    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);

    if ( _authEnabled == true && _pDBMng->verifyAccess(tabSetId, viewName, CegoObject::VIEW, CegoXMLSpace::MODIFY, _authUser) == false )
    {
	Chain msg = Chain("Access not allowed for object ") + viewName;
	throw Exception(EXLOC, msg); 
    }

    createLocalView(tabSetId, viewName,  schema, viewText);
}


void CegoQueryManager::createLocalView(unsigned tabSetId, const Chain& viewName, const ListT<CegoField>& schema, const Chain& viewText)
{
    CegoViewObject vo( tabSetId, viewName, schema, viewText);

    CegoLogRecord lr;
    lr.setLSN(_pDBMng->nextLSN(tabSetId));
    
    createViewObject(vo);
    
    // create log entry
    lr.setObjectInfo(vo.getName(), vo.getType());
    lr.setAction(CegoLogRecord::LOGREC_CREATE);
 
    char *buf;
    buf = (char*)malloc(vo.getEntrySize());
    vo.encode(buf);
    lr.setData(buf);
    lr.setDataLen(vo.getEntrySize());
    // lr.setTID(0);
    _pDBMng->logIt(vo.getTabSetId(), lr, _pLockHandle);
    free(buf);

    _pDBMng->addObject(tabSetId, viewName, CegoObject::VIEW);
}


void CegoQueryManager::createQueryTrigger(const Chain& tableSet, const Chain& triggerName,
					bool isBefore, bool isOnInsert, bool isOnUpdate, bool isOnDelete,
					const Chain& tableName, const Chain& triggerText)
{
#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Creating global trigger ") + triggerName + Chain(" in tableset ") + tableSet);
#endif

    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);

    if ( _authEnabled == true && _pDBMng->verifyAccess(tabSetId, triggerName, CegoObject::TRIGGER, CegoXMLSpace::MODIFY, _authUser) == false )
    {
	Chain msg = Chain("Access not allowed for object ") + triggerName;
	throw Exception(EXLOC, msg); 
    }

    createTrigger(tabSetId, triggerName, isBefore, isOnInsert, isOnUpdate, isOnDelete, tableName, triggerText);
    
    _pDBMng->addObject(tabSetId, triggerName, CegoObject::TRIGGER);
    
}


void CegoQueryManager::createQueryAlias(const Chain& tableSet, const Chain& aliasName,				 
				  const Chain& tableName, const ListT<CegoAttrAlias>& aliasList)
{

#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Creating global alias ") + aliasName + Chain(" in tableset ") + tableSet);
#endif

    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);

    if ( _authEnabled == true && _pDBMng->verifyAccess(tabSetId, aliasName, CegoObject::ALIAS, CegoXMLSpace::MODIFY, _authUser) == false )
    {
	Chain msg = Chain("Access not allowed for object ") + aliasName;
	throw Exception(EXLOC, msg); 
    }

    createAlias(tabSetId, aliasName, tableName, aliasList);    
    _pDBMng->addObject(tabSetId, aliasName, CegoObject::ALIAS);
    
}


void CegoQueryManager::createQueryProc(const Chain& tableSet, const Chain& procName, const Chain& procText)
{
#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Creating global procedure ") + procName + Chain(" in tableset ") + tableSet);
#endif

    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);

    if ( _authEnabled == true && _pDBMng->verifyAccess(tabSetId, procName, CegoObject::PROCEDURE, CegoXMLSpace::MODIFY, _authUser) == false )
    {
	Chain msg = Chain("Access not allowed for object ") + procName;
	throw Exception(EXLOC, msg); 
    }

    CegoProcObject po(tabSetId, procName, procText);

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

    // create log entry

    lr.setObjectInfo(po.getName(), po.getType());
    lr.setAction(CegoLogRecord::LOGREC_CREATE);
 
    char *buf;
    buf = (char*)malloc(po.getEntrySize());
    po.encode(buf);
    lr.setData(buf);
    lr.setDataLen(po.getEntrySize());
    // lr.setTID(0);
    _pDBMng->logIt(po.getTabSetId(), lr, _pLockHandle);
    free(buf);

    _pDBMng->addObject(tabSetId,procName, CegoObject::PROCEDURE);
    
}

CegoLockHandler* CegoQueryManager::getLockHandle()
{
    return _pLockHandle;
}

void CegoQueryManager::enableAuth()
{
    _authEnabled = true;
}

void CegoQueryManager::disableAuth()
{
    _authEnabled = false;
}

void CegoQueryManager::setActiveUser(const Chain& tableSet, const Chain& user, const Chain& passwd)
{
    _authUser = user;

    if ( _userList.Find(ActiveTSUser(tableSet)) == 0 )
	_userList.Insert( ActiveTSUser(tableSet, user, passwd));
}

const Chain& CegoQueryManager::getUser() const
{
    return _authUser;
}

void CegoQueryManager::getActiveUser(const Chain& tableSet, Chain& user, Chain& passwd)
{
    ActiveTSUser *pTSA = _userList.Find( ActiveTSUser(tableSet));
    if ( pTSA )
    {
	user = pTSA->getUserName();
	passwd = pTSA->getPasswd();
	return;
    }

    Chain msg = Chain("No active user for tableset <") + tableSet + Chain(">");
    throw Exception(EXLOC, msg);
}

bool CegoQueryManager::verifyTable(const Chain& tableSet, const Chain& tableName, CegoAdminHandler *pAH)
{   
    _pDBMng->log(_modId, Logger::NOTICE, Chain("Verifying table ") + tableName + Chain(" ..."));

    bool isValid = true;
    
    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);
        
    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 oe;
    getObject(tabSetId, tableName, CegoObject::TABLE, oe);
    	
    CegoTableCursor tc(this, tabSetId, tableName);
    ListT<CegoField> fl = oe.getSchema();
    CegoDataPointer dp;
    long tabCount = 0;

    Chain tableStatus;

    if ( tc.getFirst(fl, dp) )
    {
	tabCount++;
	
	isValid = checkChecks(fl, checkList, tableStatus);
	
	while ( tc.getNext(fl, dp) && isValid )
	{
	    isValid = checkChecks(fl, checkList, tableStatus);
	    
	    tabCount++;
	    
	    if ( tabCount % 1000 == 0 )
		pAH->sendInfo(Chain("... ") + Chain(tabCount) + Chain(" rows") + Chain("\r"));
	}	
    }
    
    pAH->sendInfo(Chain("... ") + Chain(tabCount) + Chain(" rows") + Chain("\n"));
    
    if ( isValid )
    {
	// verify keys
	bool keyCheck = checkKey(tabSetId, tableName, oe.getSchema(), keyList, pAH);
	
	if ( keyCheck == false )
	{
	    isValid=false;
	    
	    tableStatus = Chain("Key constraint violation");
	}
    }
    
    // verify indexes
    CegoTableObject *pIdx = idxList.First();
    while ( pIdx && isValid ) 
    {
	if ( pIdx->isValid() )
	{
	    CegoAVLIndexManager idxMng(this);
	    char c = idxMng.checkIndex(tabSetId, pIdx->getName(), pIdx->getType());
	    
	    if ( c < 0 )
	    {
		isValid=false;
		tableStatus = Chain("Index ") + pIdx->getName() + Chain(" due to height corrupted ");
	    }
	    
	    CegoAVLIndexCursor ic(this, tabSetId, pIdx->getName(), pIdx->getType(), 0, false, false);
	    
	    ListT<CegoField> fl = oe.getSchema();
	    CegoDataPointer dp;

	    unsigned long idxCount = 0;
	    
	    if ( ic.getFirst(fl, dp) )
	    {       	
		while ( ic.getNext(fl, dp) )
		{
		    if ( idxCount % 1000 == 0 )
			pAH->sendInfo(Chain("... ") + Chain(idxCount) + Chain(" avl") + Chain("\r"));
		    
		    idxCount++;
		}
			    pAH->sendInfo(Chain("... ") + Chain(idxCount) + Chain(" avl") + Chain("\n"));
	    }
	    if ( tabCount != idxCount )
	    {
		isValid=false;
		tableStatus = Chain("Index ") + pIdx->getName() + Chain(" row mismatch (") + Chain(tabCount) + Chain("/") + Chain(idxCount+1) + Chain(")");
	    }
	}
	else
	{
	    isValid=false;
	    tableStatus = Chain("Index ") + pIdx->getName() + Chain(" not valid");	    
	    
	}
	
	pIdx = idxList.Next();
    }

    // verify btree objects
    CegoBTreeObject *pBTree = btreeList.First();
    while ( pBTree && isValid ) 
    {
	if ( pBTree->isValid() )
	{
	    CegoBTreeManager btreeMng(this, pBTree);
	    if ( btreeMng.verifyBTree(pAH) == false )
	    {
		isValid=false;
		tableStatus = Chain("Btree ") + pBTree->getName() + Chain(" node corruption ");		
	    }

	    if ( isValid )
	    {
		CegoBTreeCursor bc(this, tabSetId, pBTree->getName(), pBTree->getType(), 0, false, false);
		
		ListT<CegoField> fl = oe.getSchema();
		CegoDataPointer dp;
		long btreeCount = 0;
		if ( bc.getFirst(fl, dp) )
		{
		    btreeCount++;
		    while ( bc.getNext(fl, dp) )
		    {			
			if ( btreeCount % 1000 == 0 )
			    pAH->sendInfo(Chain("... ")
					  + Chain(btreeCount)
					  + Chain(" " )
					  + pBTree->getName()
					  + Chain(" entries") + Chain("\r"));
			
			btreeCount++;
		    }		    
		    pAH->sendInfo(Chain("... ")
				  + Chain(btreeCount)
				  + Chain(" " )
				  + pBTree->getName()
				  + Chain(" entries") + Chain("\n"));		    
		}
		if ( tabCount != btreeCount )
		{
		    isValid=false;
		    tableStatus = Chain("Btree ") + pBTree->getName() + Chain(" row mismatch (") + Chain(tabCount) + Chain("/") + Chain(btreeCount) + Chain(")");
		}
	    }
	}
	else
	{
	    isValid=false;
	    tableStatus = Chain("Btree ") + pBTree->getName() + Chain(" not valid");
	}	
	pBTree = btreeList.Next();
    }


    // verify trigger objects

    CegoTriggerObject *pTrigger =  triggerList.First();
    while ( pTrigger && isValid )
    {
    
	Chain loadString = Chain("load ") + pTrigger->toChain() + Chain(";");
		
	try 
	{
	    CegoAction *pPA = getParser();
	    Chain tableSet = _pDBMng->getTabSetName(tabSetId);
	    pPA->setTableSet(tableSet);
	    pPA->setCommandChain(loadString);
	    pPA->parse();

	    // don't set trigger to null to avoid memory leak
	    CegoTrigger* pTrigger = pPA->getTrigger(false);
	    // what can we check with compiled trigger ?

	    pAH->sendInfo(Chain("... ") + Chain("trigger ") + pTrigger->getName() + Chain("\n"));
	}
	catch ( Exception e )
	{	    
	    // Chain msg;
	    // e.pop(msg);

	    tableStatus = Chain("Trigger ") + pTrigger->getName() + Chain(" not valid");
	    isValid=false;
	}

	pTrigger =  triggerList.Next();
    }

    // verify alias objects

    CegoAliasObject *pAlias =  aliasList.First();
    while ( pAlias && isValid )
    {

	// cout << "Alias Schema size = " << to.getSchema().Size() << endl;
	pAlias->setSchema(oe.getSchema());

	try
	{
	    // modify schema with alias definitons
	    pAlias->mapSchema();

	    pAH->sendInfo(Chain("... ") + Chain("alias ") + pAlias->getName() + Chain("\n"));
	}
	catch ( Exception e )
	{
	    isValid=false;
	    tableStatus = Chain("Alias ") + pAlias->getName() + Chain(" not valid");
	}


	
	pAlias =  aliasList.Next();
    }

    if ( isValid == false )
	pAH->sendInfo(Chain("... ### ") + tableStatus + Chain(" ###\n"));
    
    return isValid;
}

bool CegoQueryManager::verifyView(const Chain& tableSet, const Chain& viewName, CegoAdminHandler *pAH)
{
    try
    {

	unsigned tabSetId = _pDBMng->getTabSetId(tableSet);
	
	CegoViewObject vo;
	getObject(tabSetId, viewName, CegoObject::VIEW, vo);
    
	Chain loadString = Chain("load ") + vo.getViewStmt();
    
	CegoAction *pPA = getParser();
	pPA->cleanUp();
	pPA->setTableSet(tableSet);
	pPA->setCommandChain(loadString);
	pPA->parse();
    }
    catch ( Exception e )
    {
	Chain msg;
	e.pop(msg);
	pAH->sendInfo(Chain("... ### ") + msg + Chain(" ###\n"));
	return false;
    }

    return true;
    
}

bool CegoQueryManager::verifyProcedure(const Chain& tableSet, const Chain& procName, CegoAdminHandler *pAH)
{
    try
    {
	
	unsigned tabSetId = _pDBMng->getTabSetId(tableSet);    
	
	CegoProcObject po;
	getObject(tabSetId, procName, CegoObject::PROCEDURE, po);
	
	Chain loadString = Chain("load ") + po.getProcText();
	
	CegoAction *pPA = getParser();
	pPA->cleanUp();
	pPA->setTableSet(tableSet);
	pPA->setCommandChain(loadString);
	pPA->parse();
    }
    catch ( Exception e )
    {
	Chain msg;
	e.pop(msg);
	pAH->sendInfo(Chain("... ### ") + msg + Chain(" ###\n"));
	return false;
    }

    return true;
}

unsigned CegoQueryManager::correctTable(const Chain& tableSet, const Chain& tableName)
{   
    _pDBMng->log(_modId, Logger::NOTICE, Chain("Correcting table ") + tableName + Chain(" ..."));

    unsigned tabSetId = _pDBMng->getTabSetId(tableSet);
    
    unsigned correctCount = 0;
    
    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);
    
    // correct indexes
    CegoTableObject *pIdx = idxList.First();
    while ( pIdx ) 
    {
	if ( pIdx->isValid() == false )
	{
	    correctCount++;

	    dropIndex(tabSetId, pIdx->getName());
	    bool isCached=false;
	    createIndexTable(tabSetId, pIdx->getName(), pIdx->getTabName(), pIdx->getSchema(), pIdx->getType(), isCached);	    
	}
	
	pIdx = idxList.Next();
    }
    
    // correct btrees
    CegoBTreeObject *pBTree = btreeList.First();
    while ( pBTree ) 
    {	
	if ( pBTree->isValid() == false )
	{
	    correctCount++;
	    
	    dropBTree(tabSetId, pBTree->getName());
	    bool doSync=false;
	    bool isCached=false;
	    createBTree(tabSetId, pBTree->getName(), pBTree->getTabName(), pBTree->getSchema(), pBTree->getType(), doSync, isCached);
	    
	}
	pBTree = btreeList.Next();
    }
        
    return correctCount;
}


bool CegoQueryManager::checkChecks(ListT<CegoField>& fl, const ListT<CegoCheckObject>& checkList, Chain& checkStatus) 
{
    CegoCheckObject* pCheck = checkList.First();
    while ( pCheck )
    {	      
	pCheck->getPredDesc()->clearAttrCache();
	
	// we need to create an additional reference to call evalPredicate
	ListT<CegoField>* xfl[2];
	xfl[0] = &fl;
	xfl[1] = 0;	     
	
	if ( pCheck->getPredDesc()->eval(0, 0, xfl, 0, 0) == false )
	{
	    checkStatus = Chain("Check ") + pCheck->getName() + Chain(" violated");
	    return false;
	}
	
	pCheck = checkList.Next();
    }
    return true;
}

bool CegoQueryManager::checkKey(unsigned tabSetId, const Chain& tableName, const ListT<CegoField>& schema, const ListT<CegoKeyObject>& keyList, CegoAdminHandler* pAH)
{    
    CegoKeyObject* pKey = keyList.First();
    while ( pKey )
    {
	unsigned long count=0;
	
        if ( (Chain)pKey->getTabName() == (Chain)tableName )
        {
            CegoTableCursor ktc(this, tabSetId, pKey->getRefTable());

	    CegoTableObject oe;
	    getObject(tabSetId, pKey->getTabName(), CegoObject::TABLE, oe);
           
            ListT<CegoField> kfl = oe.getSchema();

            CegoDataPointer dp;
            bool moreTuple = ktc.getFirst(kfl, dp);
    
	    while ( moreTuple )
	    {

		if ( count % 1000 == 0 )
		    pAH->sendInfo(Chain("... ") + Chain(count) + Chain(" fkey for ") + pKey->getRefTable() + Chain("\r"));

		count++;
		
		ListT<CegoField> rfl = pKey->getRefSchema();
		CegoField *pKF = kfl.First();
		CegoField* pRF = rfl.First();
		while ( pKF && pRF)
		{
		    pRF->setValue(pKF->getValue());		    
		    pKF = kfl.Next();		    
		    pRF = rfl.Next();
		}
		
		CegoAttrCond ac;
		pRF = rfl.First();
		while ( pRF )
		{
		    // cout << "Searching for " << pRF->getTableName() << "." << pRF->getAttrName() << " = " << pRF->getValue() << endl;
		    ac.add(CegoAttrComp(pRF->getTableName(), pRF->getAttrName(), EQUAL, pRF->getValue()));		    
		    pRF = rfl.Next();
		}

		
		CegoTableCursor rtc(this, tabSetId, pKey->getRefTable());
		// no need for indexMatch value : CegoAttrCond::IndexMatch indexMatch = rtc.setup(ac);
		rtc.setup(ac);
		
		if (  rtc.getFirst(rfl, dp) == false )
		    return false;
		
		
		moreTuple = ktc.getNext(kfl, dp);		
            }
	    pAH->sendInfo(Chain("... ") + Chain(count) + Chain(" fkey for ") + pKey->getRefTable() + Chain("\n"));
	}

	pKey = keyList.Next();
    }
    return true;    
}
		
void CegoQueryManager::getObjectDesc(const Chain& tableSet, const Chain& objName, CegoObject::ObjectType type, 
				     ListT<CegoField>& schema, ListT< ListT<CegoFieldValue> > &fa)
{

    unsigned tabSetId = getDBMng()->getTabSetId(tableSet);
    
    switch ( type )
    {
    case CegoObject::SYSTEM:
    case CegoObject::TABLE:
    {
	CegoTableObject to;

	
	getObject(tabSetId, objName, type, to);
	
	unsigned maxAttrLen=10;
	CegoField *pF = to.getSchema().First();
	while ( pF )
	{
	    if ( (unsigned)pF->getAttrName().length() > maxAttrLen )
		maxAttrLen = pF->getAttrName().length();
	    pF = to.getSchema().Next();
	}
	    
	schema.Insert(CegoField(Chain("TABLEDESC"), Chain("TABLEDESC"), Chain("ATTR"), VARCHAR_TYPE, maxAttrLen));
	schema.Insert(CegoField(Chain("TABLEDESC"), Chain("TABLEDESC"), Chain("TYPE"), VARCHAR_TYPE, 10));
	schema.Insert(CegoField(Chain("TABLEDESC"), Chain("TABLEDESC"), Chain("LENGTH"), VARCHAR_TYPE, 10));
	schema.Insert(CegoField(Chain("TABLEDESC"), Chain("TABLEDESC"), Chain("DIM"), VARCHAR_TYPE, 10));
	schema.Insert(CegoField(Chain("TABLEDESC"), Chain("TABLEDESC"), Chain("DEFAULT"), VARCHAR_TYPE, 10));
	schema.Insert(CegoField(Chain("TABLEDESC"), Chain("TABLEDESC"), Chain("NULLABLE"), VARCHAR_TYPE, 10));

	pF = to.getSchema().First();
	while ( pF )
	{
	    ListT<CegoFieldValue> fvl;	    
	   
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, pF->getAttrName()));
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, CegoTypeConverter::getTypeString(pF->getType())));
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, Chain(pF->getLength())));
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, Chain(pF->getDim())));
	    
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, pF->getValue().valAsChain(false)));
	    
	    if ( pF->isNullable() )
		fvl.Insert(CegoFieldValue(VARCHAR_TYPE, Chain("yes")));
	    else
		fvl.Insert(CegoFieldValue(VARCHAR_TYPE, Chain("no")));
	    
	    fa.Insert(fvl);
	    
	    pF = to.getSchema().Next();
	}
	break;
    }
    case CegoObject::AVLTREE:
    case CegoObject::UAVLTREE:
    case CegoObject::PAVLTREE:
    {
	CegoTableObject io;
	getObject(tabSetId, objName, type, io);
	
	unsigned maxAttrLen=10;
	CegoField *pF = io.getSchema().First();
	while ( pF )
	{
	    if ( (unsigned)pF->getAttrName().length() > maxAttrLen )
		maxAttrLen = pF->getAttrName().length();
	    pF = io.getSchema().Next();
	}

	unsigned maxTabLen=10;	
	if ( (unsigned)io.getTabName().length() > maxTabLen )
	    maxTabLen = io.getTabName().length();
	    
	schema.Insert(CegoField(Chain("INDEXDESC"), Chain("TABLEDESC"), Chain("ATTR"), VARCHAR_TYPE, maxAttrLen));
	schema.Insert(CegoField(Chain("INDEXDESC"), Chain("TABLEDESC"), Chain("TABLE"), VARCHAR_TYPE, maxTabLen));
	schema.Insert(CegoField(Chain("INDEXDESC"), Chain("TABLEDESC"), Chain("TYPE"), VARCHAR_TYPE, 10));
	
	pF = io.getSchema().First();
	while ( pF )
	{
	    ListT<CegoFieldValue> fvl;	    
	   
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, pF->getAttrName()));
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, io.getTabName()));
	    
	    if ( io.getType() == CegoObject::AVLTREE) 
		fvl.Insert(CegoFieldValue(VARCHAR_TYPE, XML_INDEX_VALUE));
	    else if ( io.getType() == CegoObject::PAVLTREE)
		fvl.Insert(CegoFieldValue(VARCHAR_TYPE, XML_PINDEX_VALUE));
	    else if ( io.getType() == CegoObject::UAVLTREE)
		fvl.Insert(CegoFieldValue(VARCHAR_TYPE, XML_UINDEX_VALUE));
	    
	    fa.Insert(fvl);
	    
	    pF = io.getSchema().Next();
	}
	break;
    }
    case CegoObject::BTREE:
    case CegoObject::UBTREE:
    case CegoObject::PBTREE:
    {
	CegoBTreeObject bto;
	getObject(tabSetId, objName, type, bto);
	
	unsigned maxAttrLen=10;
	CegoField *pF = bto.getSchema().First();
	while ( pF )
	{
	    if ( (unsigned)pF->getAttrName().length() > maxAttrLen )
		maxAttrLen = pF->getAttrName().length();
	    pF = bto.getSchema().Next();
	}

	unsigned maxTabLen=10;	
	if ( (unsigned)bto.getTabName().length() > maxTabLen )
	    maxTabLen = bto.getTabName().length();
	    
	schema.Insert(CegoField(Chain("BTREEDESC"), Chain("TABLEDESC"), Chain("ATTR"), VARCHAR_TYPE, maxAttrLen));
	schema.Insert(CegoField(Chain("BTREEDESC"), Chain("TABLEDESC"), Chain("TABLE"), VARCHAR_TYPE, maxTabLen));
	schema.Insert(CegoField(Chain("BTREEDESC"), Chain("TABLEDESC"), Chain("TYPE"), VARCHAR_TYPE, 10));
	
	pF = bto.getSchema().First();
	while ( pF )
	{
	    ListT<CegoFieldValue> fvl;
	   
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, pF->getAttrName()));
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, bto.getTabName()));
	    
	    if ( bto.getType() == CegoObject::BTREE) 
		fvl.Insert(CegoFieldValue(VARCHAR_TYPE, XML_BTREE_VALUE));
	    else if ( bto.getType() == CegoObject::PBTREE)
		fvl.Insert(CegoFieldValue(VARCHAR_TYPE, XML_PBTREE_VALUE));
	    else if ( bto.getType() == CegoObject::UBTREE)
		fvl.Insert(CegoFieldValue(VARCHAR_TYPE, XML_UBTREE_VALUE));
	    
	    fa.Insert(fvl);
	    
	    pF = bto.getSchema().Next();
	}
	break;
    }
    case CegoObject::VIEW:
    {
	CegoViewObject vo;
	getObject(tabSetId, objName, type, vo);

	unsigned maxAttrLen=10;
	CegoField *pF = vo.getSchema().First();
	while ( pF )
	{
	    if ( (unsigned)pF->getAttrName().length() > maxAttrLen )
		maxAttrLen = pF->getAttrName().length();
	    pF = vo.getSchema().Next();
	}

	schema.Insert(CegoField(Chain("VIEWDESC"), Chain("VIEWDESC"), Chain("ATTR"), VARCHAR_TYPE, maxAttrLen));
	schema.Insert(CegoField(Chain("VIEWDESC"), Chain("VIEWDESC"), Chain("TYPE"), VARCHAR_TYPE, 10));
	schema.Insert(CegoField(Chain("VIEWDESC"), Chain("VIEWDESC"), Chain("LENGTH"), VARCHAR_TYPE, 10));
	schema.Insert(CegoField(Chain("VIEWDESC"), Chain("VIEWDESC"), Chain("DIM"), VARCHAR_TYPE, 10));

	pF = vo.getSchema().First();
	while ( pF )
	{
	    ListT<CegoFieldValue> fvl;
	    
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, pF->getAttrName()));
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, CegoTypeConverter::getTypeString(pF->getType())));
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, Chain(pF->getLength())));
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, Chain(pF->getDim())));
	    
	    fa.Insert(fvl);

	    pF = vo.getSchema().Next();
	}
	break;
    }
    case CegoObject::PROCEDURE:
    {

	if ( checkCompProcedure(tabSetId, objName) == false )
	    reloadProcedure( tabSetId, objName );

	CegoProcedure* pProc = getCompProcedure(tabSetId, objName);

	ListT<CegoProcVar> argList;
	pProc->getArgList(argList);

	unsigned maxAttrLen=10;
	CegoProcVar *pArg = argList.First();
	while ( pArg )
	{
	    if ( (unsigned)pArg->getName().length() > maxAttrLen )
		maxAttrLen = pArg->getName().length();
	    pArg = argList.Next();
	}

	schema.Insert(CegoField(Chain("PROCDESC"), Chain("PROCDESC"), Chain("ATTR"), VARCHAR_TYPE, maxAttrLen));
	schema.Insert(CegoField(Chain("PROCDESC"), Chain("PROCDESC"), Chain("TYPE"), VARCHAR_TYPE, 10));
	schema.Insert(CegoField(Chain("PROCDESC"), Chain("PROCDESC"), Chain("LENGTH"), VARCHAR_TYPE, 10));
	schema.Insert(CegoField(Chain("PROCDESC"), Chain("PROCDESC"), Chain("DIM"), VARCHAR_TYPE, 10));
	schema.Insert(CegoField(Chain("PROCDESC"), Chain("PROCDESC"), Chain("INOUT"), VARCHAR_TYPE, 10));
	
	pArg = argList.First();
	while ( pArg )
	{
	    ListT<CegoFieldValue> fvl;	    

	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, pArg->getName()));
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, CegoTypeConverter::getTypeString(pArg->getType())));	  
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, Chain(pArg->getLength())));
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, Chain(pArg->getDim())));
	    		       
	    if ( pArg->getVarType() == CegoProcVar::INVAR )
		fvl.Insert(CegoFieldValue(VARCHAR_TYPE, Chain("in")));
	    else if ( pArg->getVarType() == CegoProcVar::OUTVAR )
		fvl.Insert(CegoFieldValue(VARCHAR_TYPE, Chain("out")));
	    else
		fvl.Insert(CegoFieldValue(VARCHAR_TYPE, Chain("n/a")));

	    fa.Insert(fvl);

	    pArg = argList.Next();
	}
	break;
    }
    case CegoObject::FKEY:
    {	    
	CegoKeyObject ko;
	getObject(tabSetId, objName, type, ko);
	
	unsigned maxTabLen=10;
	if ( (unsigned)objName.length() > maxTabLen )
	    maxTabLen = objName.length();
	
	unsigned maxAttrLen=10;
	CegoField *pK = ko.getKeySchema().First();
	while ( pK )
	{
	    if ( (unsigned)pK->getAttrName().length() > maxAttrLen )
		maxAttrLen = pK->getAttrName().length();
	    
	    pK = ko.getKeySchema().Next();
	}
	CegoField *pR = ko.getRefSchema().First();
	while ( pR )
	{
	    if ( (unsigned)pR->getAttrName().length() > maxAttrLen )
		maxAttrLen = pR->getAttrName().length();
	    pR = ko.getRefSchema().Next();
	}	
	
	schema.Insert(CegoField(Chain("KEYDESC"), Chain("KEYDESC"), Chain("TABLE"), VARCHAR_TYPE, maxTabLen));
	schema.Insert(CegoField(Chain("KEYDESC"), Chain("KEYDESC"), Chain("ATTR"), VARCHAR_TYPE, maxAttrLen));
	schema.Insert(CegoField(Chain("KEYDESC"), Chain("KEYDESC"), Chain("TYPE"), VARCHAR_TYPE, 10));

	pK = ko.getKeySchema().First();
	while ( pK )
	{
	    ListT<CegoFieldValue> fvl;	    
	    
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, ko.getTabName()));
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, pK->getAttrName()));
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, Chain("key")));
	    
	    fa.Insert(fvl);

	    pK = ko.getKeySchema().Next();
	}
	pR = ko.getRefSchema().First();
	while ( pR )
	{
	    ListT<CegoFieldValue> fvl;	    
	    
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, ko.getRefTable()));
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, pR->getAttrName()));
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, Chain("reference")));
	    
	    fa.Insert(fvl);

	    pR = ko.getRefSchema().Next();
	}	
	break;
    }
    case CegoObject::CHECK:
    {
	CegoCheckObject co;
	getObject(tabSetId, objName, type, co);
	    
	unsigned maxTabLen=10;
	if ( (unsigned)objName.length() > maxTabLen )
	    maxTabLen = objName.length();
	
	unsigned maxCheckLen=30;
	schema.Insert(CegoField(Chain("CHECKDESC"), Chain("CHECKDESC"), Chain("TABLE"), VARCHAR_TYPE, maxTabLen));
	schema.Insert(CegoField(Chain("CHECKDESC"), Chain("CHECKDESC"), Chain("CONDITION"), VARCHAR_TYPE, maxCheckLen));

	ListT<CegoFieldValue> fvl;
	
	fvl.Insert(CegoFieldValue(VARCHAR_TYPE, co.getTabName()));
	fvl.Insert(CegoFieldValue(VARCHAR_TYPE, co.getPredDesc()->toChain(tabSetId)));

	fa.Insert(fvl);

	break;
    }
    case CegoObject::TRIGGER:
    {
	CegoTriggerObject to;
	getObject(tabSetId, objName, type, to);
	
	unsigned maxTabLen=10;
	if ( (unsigned)objName.length() > maxTabLen )
	    maxTabLen = objName.length();
	
	unsigned maxCheckLen=30;
	schema.Insert(CegoField(Chain("TRIGGERDESC"), Chain("TRIGGERDESC"), Chain("TABLE"), VARCHAR_TYPE, maxTabLen));
	schema.Insert(CegoField(Chain("TRIGGERDESC"), Chain("TRIGGERDESC"), Chain("TRIGGERTEXT"), VARCHAR_TYPE, maxCheckLen));

	ListT<CegoFieldValue> fvl;
	
	fvl.Insert(CegoFieldValue(VARCHAR_TYPE, to.getTabName()));
	fvl.Insert(CegoFieldValue(VARCHAR_TYPE, to.getTriggerText()));

	fa.Insert(fvl);

	break;
    }
    case CegoObject::ALIAS:
    {
	CegoAliasObject ao;
	getObject(tabSetId, objName, type, ao);
	
	unsigned maxTabLen=10;
	if ( (unsigned)objName.length() > maxTabLen )
	    maxTabLen = objName.length();
	
	unsigned maxAliasLen=30;
	schema.Insert(CegoField(Chain("ALIASDESC"), Chain("ALIASDESC"), Chain("TABLE"), VARCHAR_TYPE, maxTabLen));
	schema.Insert(CegoField(Chain("ALIASDESC"), Chain("ALIASDESC"), Chain("ATTRIBUTE"), VARCHAR_TYPE, maxAliasLen));
	schema.Insert(CegoField(Chain("ALIASDESC"), Chain("ALIASDESC"), Chain("ALIAS"), VARCHAR_TYPE, maxAliasLen));

	CegoAttrAlias *pAlias = ao.getAliasList().First();
	while ( pAlias )
	{
	    ListT<CegoFieldValue> fvl;
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, ao.getTabName()));
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, pAlias->getAttrName()));
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, pAlias->getAliasName()));
	    fa.Insert(fvl);
	    pAlias = ao.getAliasList().Next();
	}
		       
	break;
    }
    case CegoObject::RBSEG:
    case CegoObject::JOIN:
    case CegoObject::UNDEFINED:	
    {
	throw Exception(EXLOC, Chain("Cannot get description for object type"));
    }
    }
}

CegoView* CegoQueryManager::getView(unsigned tabSetId, const Chain& viewName)
{
    if ( checkCompView(tabSetId, viewName) == false )
	reloadView( tabSetId, viewName );
    return getCompView(tabSetId, viewName );
}


CegoProcedure* CegoQueryManager::getProcedure(unsigned tabSetId, const Chain& procName)
{
    if ( checkCompProcedure(tabSetId, procName) == false )
	reloadProcedure( tabSetId, procName );
    return getCompProcedure(tabSetId, procName );
}

CegoAction* CegoQueryManager::getParser()
{
    if ( _pPA == 0 )
    {
	_pPA = new CegoAction(this);
	_pPA->setGraceMode(_isGrace);
    }
	
    return _pPA;
}

void CegoQueryManager::reloadView(unsigned tabSetId, const Chain& viewName)
{
    CegoViewObject vo;
    getObject(tabSetId, viewName, CegoObject::VIEW, vo);

    Chain loadString = Chain("load ") + vo.getViewStmt();

    // since this message is produced for each database thread, we avoid this
    // _pDBMng->log(_modId, Logger::NOTICE, Chain("View ") + viewName + Chain(" is reloaded"));

    // since views can be nested, we have to use dedicated parser here
    // in this phase by using view objects ( instead of creating it),
    // no grace mode is allowed and treated
    CegoAction *pPA = new CegoAction(this);
	
    try
    {	
	Chain tableSet = _pDBMng->getTabSetName(tabSetId);
	
	pPA->setTableSet(tableSet);
	pPA->setCommandChain(loadString);
	pPA->parse();	
	CegoSelect* pSelect = pPA->getSelect(true);
       
	CegoView *pView = new CegoView(viewName, pSelect);

	pSelect->setTabSetId(tabSetId);

	pSelect->prepare();
	
	ListT<CegoField> schema;
	pSelect->getSchema(schema);

	addCompView(tabSetId, pView);

	// if schema is zero, recompile is required
	if ( vo.getSchema().Size() == 0 )
	{
	    _pDBMng->log(_modId, Logger::NOTICE, Chain("View ") + viewName + Chain(" detected as invalid"));

	    dropView(tabSetId, viewName);
	    Chain viewStmt = Chain("view ") + viewName + Chain(" as\n") + pSelect->toChain(tabSetId) + Chain(";");
	    createLocalView( tabSetId, viewName, schema, viewStmt);
	    
	    _pDBMng->log(_modId, Logger::NOTICE, Chain("View ") + viewName + Chain(" validated sucessful"));
	}	
    }
    catch ( Exception e )
    {
	if ( pPA )
	    delete pPA;
	
	Chain msg = Chain("Cannot load view ") + viewName; 
	throw Exception(EXLOC, msg, e);
    }

    delete pPA;
}

void CegoQueryManager::reloadProcedure(unsigned tabSetId, const Chain& procName)
{    
    CegoProcObject po;
    getObject(tabSetId, procName, CegoObject::PROCEDURE, po);
    
    Chain loadString = Chain("load ") + po.getProcText();

    // cout << "Load String = " << loadString << endl;
    // since this message is produced for each database thread, we avoid this
    // _pDBMng->log(_modId, Logger::NOTICE, Chain("Procedure ") + procName + Chain(" is reloaded"));        

    // since procedures can be nested, we have to use dedicated parser here
    CegoAction *pPA = new CegoAction(this);
    
    try 
    {
	Chain tableSet = _pDBMng->getTabSetName(tabSetId);
	pPA->setTableSet(tableSet);
	pPA->setCommandChain(loadString);
	pPA->parse();
	
	CegoProcedure* pProc = pPA->getProcedure(true);

	pProc->enableProcCache(_pDBMng->getProcCacheEnabled(tabSetId));
	
	addCompProcedure(tabSetId, pProc);
    }
    catch ( Exception e )
    {
	if ( pPA )
	    delete pPA;
	
	Chain msg = Chain("Cannot load procedure ") + procName; 
	throw Exception(EXLOC, msg, e);
    }

    delete pPA;
}


CegoTrigger* CegoQueryManager::getTrigger(unsigned tabSetId, const Chain& triggerName)
{
    if ( checkCompTrigger(tabSetId, triggerName) == false )
	reloadTrigger( tabSetId, triggerName );
    
    return getCompTrigger(tabSetId, triggerName );
}

void CegoQueryManager::reloadTrigger(unsigned tabSetId, const Chain& triggerName)
{    
    CegoTriggerObject to;
    getObject(tabSetId, triggerName, CegoObject::TRIGGER, to);
    
    Chain loadString = Chain("load ") + to.toChain() + Chain(";");

    // since this message is produced for each database thread, we avoid this
    // _pDBMng->log(_modId, Logger::NOTICE, Chain("Trigger ") + triggerName + Chain(" is reloaded"));        

    CegoAction *pPA = new CegoAction(this);
    
    try 
    {
	Chain tableSet = _pDBMng->getTabSetName(tabSetId);
	pPA->setTableSet(tableSet);
	pPA->setCommandChain(loadString);
	pPA->parse();
	
	CegoTrigger* pTrigger = pPA->getTrigger(true);
	
	addCompTrigger(tabSetId, pTrigger);
    }
    catch ( Exception e )
    {
	if ( pPA )
	    delete pPA;
	
	Chain msg = Chain("Cannot load trigger ") + triggerName; 
	throw Exception(EXLOC, msg, e);
    }

    delete pPA;
}

void CegoQueryManager::setGraceMode(bool isGrace)
{
    _isGrace = isGrace;
}

bool CegoQueryManager::isGraceMode() const
{
    return _isGrace;
}

CegoReplacer* CegoQueryManager::getReplacer(const Chain& pattern, const Chain& replace)
{
    CegoReplacer *pRep = _pRepHash->Find(CegoReplacer(pattern, replace));

    if ( pRep == 0 )
    {
	CegoReplacer rep(pattern, replace);
	bool wasInserted = _pRepHash->Insert(rep);
	if ( wasInserted )
	{
	    return _pRepHash->Find(CegoReplacer(pattern, replace));
	}
	else
	{
	    throw Exception(EXLOC, "Replace Hash Error");
	}
    }
    
    return pRep;
}

