///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoDistManager.cc
// ------------------
// Cego distributed table manager class implementation
//                                                         
// Design and Implementation by Bjoern Lemke               
//
// (C)opyright 2000-2010 Bjoern Lemke
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; see the file COPYING.  If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
//
// IMPLEMENTATION MODULE
//
// Class: CegoDistManager
// 
// Description: 
//
// Status: QG-2.6
//
///////////////////////////////////////////////////////////////////////////////

#include "CegoDistManager.h"

#include <lfc/Exception.h>
#include <lfc/Host.h>

#include "CegoAVLIndexCursor.h"
#include "CegoAVLIndexManager.h"
#include "CegoAction.h"
#include "CegoXMLdef.h"
#include "CegoTypeConverter.h"
#include "CegoRecoveryManager.h"

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

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

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

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

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

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

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

CegoDistManager::CegoDistManager(CegoDatabaseManager *pDBMng) : CegoTableManager(pDBMng)
{
    _modId = pDBMng->getModId("CegoDistManager");
    _authEnabled = true;
}

CegoDistManager::~CegoDistManager()
{
}

void CegoDistManager::startDistTableSet(const Chain& tableSet, const Chain& secondary, bool cleanIt)
{
    startTableSet(tableSet, secondary, cleanIt);
    registerObjects(tableSet);
}

void CegoDistManager::registerObjects(const Chain& tableSet)
{
    
    int 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::INDEX, 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::INDEX);
	pIdxName = idxList.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();
    }
}


void CegoDistManager::stopDistTableSet(const Chain& tableSet, bool archComplete)
{
    
    int 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("Removing table ") + *pTableName + Chain(" from tableset ") + tableSet);
#endif
	_pDBMng->removeObject(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("Removing view ") + *pViewName + Chain(" from tableset ") + tableSet);
#endif
	_pDBMng->removeObject(tabSetId, *pViewName, CegoObject::VIEW);
	pViewName = viewList.Next();
    }
    
    ListT<Chain> idxList;
    getObjectList(tabSetId, CegoObject::INDEX, idxList);
    Chain *pIdxName = idxList.First();
    while ( pIdxName )
    {	
#ifdef CGDEBUG
	_pDBMng->log(_modId, Logger::DEBUG, Chain("Removing index ") + *pIdxName + Chain(" from tableset ") + tableSet);
#endif
	_pDBMng->removeObject(tabSetId, *pIdxName, CegoObject::INDEX);
	pIdxName = idxList.Next();
    }

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

    stopTableSet(tableSet, archComplete);
}


void CegoDistManager::startTableSet(const Chain& tableSet, const Chain& secondary, bool cleanIt)
{

    _pDBMng->log(_modId, Logger::NOTICE, Chain("Starting tableset ") + tableSet + Chain(" ..."));

    int tabSetId = _pDBMng->getTabSetId(tableSet);
    initLock(tabSetId);
    regDataFiles(tableSet, cleanIt);

    Host h;    
    
    if ( secondary != h.getName() )
    {
	int logPort;
	_pDBMng->getLogPort(logPort);

	_pDBMng->allocateLogConnection(tabSetId, tableSet, secondary, logPort);
	long cplsn = _pDBMng->getCommittedLSN(tableSet);

	_pDBMng->setLSN(tabSetId, cplsn+1);
	_pDBMng->startLog(tabSetId);
    }
    else
    {

	_pDBMng->setActiveLogFile(tableSet);

	// get checkpoint lsn
	long cplsn = _pDBMng->getCommittedLSN(tableSet);

	// get max written lsn
	long maxlsn = _pDBMng->getMaxLSN(tabSetId);

	if ( cplsn == maxlsn || ( cplsn == 0 && maxlsn == 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  < maxlsn )
	{
	    long minlsn = _pDBMng->getMinLSN(tabSetId);
	    
	    if ( cplsn + 1 < minlsn )
	    {
		throw Exception(EXLOC, Chain("Checkpoint lsn=") + Chain(cplsn) + Chain(" is too small ( minlsn=") + Chain(minlsn) + Chain(")")); 
	    }
	    _pDBMng->log(_modId, Logger::NOTICE, Chain("Tableset ") + tableSet + Chain(" not in sync, recovery required"));    

	    _pDBMng->setLSN(tabSetId, cplsn+1);    
	    
	    long lsn;
	    int ts = 0;

	    CegoRecoveryManager recoveryMng(this, CegoRecoveryManager::LOCAL);
	    recoveryMng.recoverCurrentTransactionLog(tabSetId, 0, lsn, ts);
	    
	    if ( lsn != maxlsn )
	    {
		throw Exception(EXLOC, Chain("Incomplete recovery")); 
	    }

	    finishOpenTransaction(tabSetId);

	    // set lsn to last lsn in log
	    maxlsn = writeCheckPoint(tableSet, true, false);
	    
	}
	else
	{
	    throw Exception(EXLOC, "Checkpoint lsn is too high ( maxlsn = " + Chain(maxlsn) + ", lsn=" + Chain(cplsn) + Chain(")")); 
	}
	

	_pDBMng->log(_modId, Logger::NOTICE, Chain("Starting log for tableset ") + tableSet + Chain(" ..."));
	
	_pDBMng->setLSN(tabSetId, maxlsn+1);
	_pDBMng->startLog(tabSetId);    
    
    }

    _pDBMng->setTableSetRunState(tableSet, XML_ONLINE_VALUE); 
    _pDBMng->setTableSetSyncState(tableSet, XML_SYNCHED_VALUE); 
	
}



bool CegoDistManager::distObjectExists(const Chain& tableSet, const Chain& objName, CegoObject::ObjectType objType)
{
    int tabSetId = _pDBMng->getTabSetId(tableSet);

    Chain hostName = _pDBMng->getPrimary(tabSetId);
    
    Host h;

    if ( hostName.toUpper() == h.getName().toUpper() )
    {    
	if ( _pDBMng->objectExists(tabSetId, objName, objType) )
	    return true;
    }
    else
    {
	
	Chain user;
	Chain password;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);

	Chain msg;
	CegoDbHandler::ResultType res;
    
	res = pSH->reqObjectInfoOp(tabSetId, objName, objType);

	_pDBMng->releaseSession(pSH);
	
	if ( res == CegoDbHandler::DB_INFO )	    
	    return true;	
    }
    
    return false;
}

void CegoDistManager::getDistObject(const Chain& tableSet, const Chain& objName, CegoObject::ObjectType type, CegoDecodableObject& oe)
{

    int 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);
#endif

    Chain hostName = _pDBMng->getPrimary(tabSetId);
    
    Host h;

    if ( hostName.toUpper() == h.getName().toUpper() )
    {
	getLocalObject(tabSetId, objName, type, oe);
	oe.setLocal(true);
	oe.setTableSet(tableSet);
    }
    else
    {
	
	Chain user;
	Chain password;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);

	Chain msg;
	CegoDbHandler::ResultType res;
    
	res = pSH->reqObjectInfoOp(tabSetId, objName, type);
	
	if ( res == CegoDbHandler::DB_INFO )
	{
	    oe.putElement( pSH->getObjElement() );
	    oe.setLocal(false);
	    _pDBMng->releaseSession(pSH);	    
	    
	}
	else if ( res == CegoDbHandler::DB_ERROR )
	{
	    Chain msg = pSH->getMsg();
	    _pDBMng->releaseSession(pSH);
	    throw Exception(EXLOC, msg); 
	}
    }
}

void CegoDistManager::getLocalObject(int tabSetId, const Chain& objName, CegoObject::ObjectType type, CegoDecodableObject& oe)
{
    getObject(tabSetId, objName, type, oe);
}

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

    int 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); 
    }

    Chain hostName = _pDBMng->getPrimary(tabSetId);
    
    Host h;

    if ( hostName.toUpper() == h.getName().toUpper() )
    {
	dropLocalObject(tabSetId, objName, type);
    }
    else
    {
	
	Chain user;
	Chain password;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);
	
	Chain msg;
	CegoDbHandler::ResultType res;

	res = pSH->reqDropObjectOp(tableSet, objName, type);

	if ( res == CegoDbHandler::DB_OK )
	{
	    _pDBMng->releaseSession(pSH);	    
	}
	else if ( res == CegoDbHandler::DB_ERROR )
	{
	    Chain msg = pSH->getMsg();
	    _pDBMng->releaseSession(pSH);
	    throw Exception(EXLOC, msg); 
	}
    }
   
}

void CegoDistManager::dropLocalObject(int tabSetId, const Chain& objName, CegoObject::ObjectType type)
{    

    Chain tableName;
    bool useIt = false;
    CegoObject::ObjectType useType;

    if ( type == CegoObject::INDEX 
	 || type == CegoObject::UINDEX 
	 || type == CegoObject::PINDEX )
    {
	CegoTableObject io;
	getObject(tabSetId, objName, type, io);
	tableName = io.getTabName();
	useType=CegoObject::TABLE;
	useIt = true;
    }
    else if ( type == CegoObject::BTREE
	 || type == CegoObject::UBTREE
	 || type == CegoObject::PBTREE )
    {
	CegoBTreeObject bto;
	getObject(tabSetId, objName, type, bto);
	tableName = bto.getTabName();
	useType=CegoObject::TABLE;
	useIt = true;	
    }
    else if ( type == CegoObject::TABLE )
    {
	tableName = objName;
	useIt = true;
	useType=type;
    }
    else if ( type == CegoObject::PROCEDURE 
	      || type == CegoObject::VIEW 
	      || type == CegoObject::FKEY 
	      || type == CegoObject::CHECK
	      || type == CegoObject::RBSEG )
    {
	// no lock need via useObject
    }

    if ( useIt )
    {
	_pDBMng->useObject(tabSetId, tableName, useType, CegoDatabaseManager::EXCLUSIVE, _threadId);
    }
    
    ListT<CegoTableObject> idxList;
    ListT<CegoBTreeObject> btreeList;
    ListT<CegoKeyObject> keyList;
    ListT<CegoCheckObject> checkList;

    switch ( type )
    {
    case CegoObject::TABLE:
	dropTable(tabSetId, objName, CegoObject::TABLE, idxList, btreeList, keyList, checkList);
	break;
    case CegoObject::INDEX:
    case CegoObject::UINDEX:
    case CegoObject::PINDEX:
	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::SYSTEM:
    case CegoObject::RBSEG:
    case CegoObject::JOIN:
    case CegoObject::UNDEFINED:
	throw Exception(EXLOC, "Invalid object type for drop");
    }

    CegoTableObject *pIO = idxList.First();
    while ( pIO )
    {
	_pDBMng->removeObject(tabSetId, pIO->getName(), pIO->getType());
	pIO = idxList.Next();
    }

    CegoBTreeObject *pBTO = btreeList.First();
    while ( pBTO )
    {
	_pDBMng->removeObject(tabSetId, pBTO->getName(), pBTO->getType());
	pBTO = btreeList.Next();
    }

    CegoKeyObject *pKO = keyList.First();
    while ( pKO )
    {
	_pDBMng->removeObject(tabSetId, pKO->getName(), pKO->getType());
	pKO = keyList.Next();
    }

    CegoCheckObject *pCO = checkList.First();
    while ( pCO )
    {
	_pDBMng->removeObject(tabSetId, pCO->getName(), pCO->getType());
	pCO = checkList.Next();
    }
    
    _pDBMng->removeObject(tabSetId, objName, type);
    
    if ( tableName != objName && useIt ) 
	_pDBMng->unuseObject(tabSetId, tableName, useType, CegoDatabaseManager::EXCLUSIVE);
    
}

void CegoDistManager::createDistDataTable(const Chain& tableSet, const Chain& tableName, CegoObject::ObjectType type, 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

    Chain hostName = _pDBMng->getPrimary(tableSet);
    int tabSetId = _pDBMng->getTabSetId(tableSet);

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

    Host h;

    if ( hostName.toUpper() == h.getName().toUpper() )
    {	
	createLocalDataTable(tabSetId, tableName, CegoObject::TABLE, fldList, idxList, useColumnId);
    }
    else
    {

	Chain user;
	Chain password;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);

	CegoDbHandler::ResultType res;
	res = pSH->reqCreateTableOp(tableSet, tableName, type,  fldList, idxList);

	if ( res == CegoDbHandler::DB_OK )
	{
	    _pDBMng->releaseSession(pSH);	    
	}
	else if ( res == CegoDbHandler::DB_ERROR )
	{
	    Chain msg = pSH->getMsg();
	    _pDBMng->releaseSession(pSH);
	    throw Exception(EXLOC, msg); 
	}
    }
}

void CegoDistManager::createLocalDataTable(int tabSetId, const Chain& tableName, CegoObject::ObjectType type, ListT<CegoField>& fldList, ListT<CegoField>& idxList, bool useColumnId)
{

    createDataTable(tabSetId, tableName, type, fldList, useColumnId);

    if ( ! idxList.isEmpty() )
    {
	Chain idxName = tableName + Chain(TABMNG_PIDX_SUFFIX);
	createPrimaryIndexTable(tabSetId, idxName, tableName, idxList);
    }

    _pDBMng->addObject(tabSetId, tableName, CegoObject::TABLE);

    if ( ! idxList.isEmpty() )
    {
	Chain idxName = tableName + Chain(TABMNG_PIDX_SUFFIX);	
	_pDBMng->addObject(tabSetId, idxName, CegoObject::INDEX);	
    }

}

void CegoDistManager::createDistIndexTable( const Chain& tableSet, const Chain& indexName, const Chain& tableName, ListT<CegoField>& idxList, CegoObject::ObjectType type)
{

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


    int tabSetId = _pDBMng->getTabSetId(tableSet);

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


    Chain hostName =_pDBMng->getPrimary(tableSet);

    Host h;

    if ( hostName.toUpper() == h.getName().toUpper() )
    {
	createLocalIndexTable(tabSetId, indexName, tableName, type, idxList);
    }
    else
    {

	Chain user;
	Chain password;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);

	pSH->reqCreateIndexOp(tableSet, indexName, tableName, type, idxList);
	_pDBMng->releaseSession(pSH);
    }
}

void CegoDistManager::createLocalIndexTable(int tabSetId, const Chain& indexName, const Chain& tableName, CegoObject::ObjectType type, ListT<CegoField>& idxList)
{
    _pDBMng->useObject(tabSetId, tableName, CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE_WRITE, _threadId);

    try {
	createIndexTable(tabSetId, indexName, tableName, idxList, type);
    }
    catch ( Exception  e )
    {
	_pDBMng->unuseObject(tabSetId, tableName, CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE_WRITE);
	throw Exception(e);
    }
    _pDBMng->unuseObject(tabSetId, tableName, CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE_WRITE);

    _pDBMng->addObject(tabSetId, indexName, type);

}

void CegoDistManager::createDistForeignKey( 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

    Chain hostName = _pDBMng->getPrimary(tableSet);
    int 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); 
    }

    Host h;
    if ( hostName.toUpper() == h.getName().toUpper() )
    {
	createLocalForeignKey(tabSetId, fkey, tableName, keyList, refTable, refList);
    }
    else
    {
	Chain user;
	Chain password;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);

	pSH->reqCreateFKeyOp(tabSetId, fkey, tableName, keyList, refTable, refList);
	_pDBMng->releaseSession(pSH);
    }

}

void CegoDistManager::createLocalForeignKey(int tabSetId, const Chain& fkey, const Chain& tableName, const ListT<CegoField>& keyList, const Chain& refTable, const ListT<CegoField>& refList)
{
    createForeignKey(tabSetId, fkey, tableName, keyList, refTable, refList);

    _pDBMng->addObject(tabSetId, fkey, CegoObject::FKEY);
}

void CegoDistManager::createDistCheck( const Chain& tableSet, const Chain& checkName, const Chain& tableName, CegoPredDesc *pPredDesc)
{
#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Creating global check ") + checkName + Chain(" in tableset ") + tableSet);
#endif
    
    Chain hostName = _pDBMng->getPrimary(tableSet);
    int 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); 
    }

    Host h;
    if ( hostName.toUpper() == h.getName().toUpper() )
    {
	createLocalCheck(tabSetId, checkName, tableName, pPredDesc);
    }
    else
    {
	
	Chain user;
	Chain password;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);

	pSH->reqCreateCheckOp(tableSet, checkName, tableName, pPredDesc);
	_pDBMng->releaseSession(pSH);
    }    
}

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

void CegoDistManager::reorgDistObject(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

    Chain hostName = _pDBMng->getPrimary(tableSet);
    int 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); 
    }

    Host h;

    if ( hostName.toUpper() == h.getName().toUpper() )
    {	

	_pDBMng->useObject(tabSetId, objName, type, CegoDatabaseManager::EXCLUSIVE_WRITE, _threadId);
	
	try {

	    reorgObject(tabSetId, objName, type);
	    
	}
	catch ( Exception e )
	{
	    _pDBMng->unuseObject(tabSetId, objName, type, CegoDatabaseManager::EXCLUSIVE_WRITE);
	}

	_pDBMng->unuseObject(tabSetId, objName, type, CegoDatabaseManager::EXCLUSIVE_WRITE);

    }
    else
    {

	Chain user;
	Chain password;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);

	CegoDbHandler::ResultType res;
	res = pSH->reqReorgObjectOp(tableSet, objName, type);

	if ( res == CegoDbHandler::DB_OK )
	{
	    _pDBMng->releaseSession(pSH);	    
	}
	else if ( res == CegoDbHandler::DB_ERROR )
	{
	    Chain msg = pSH->getMsg();
	    _pDBMng->releaseSession(pSH);
	    throw Exception(EXLOC, msg); 
	}
    }
}


void CegoDistManager::startDistTransaction( const Chain& tableSet)
{

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

    Chain hostName = _pDBMng->getPrimary(tableSet);
    int tabSetId = _pDBMng->getTabSetId(tableSet);

    Host h;
    if ( hostName.toUpper() == h.getName().toUpper() )
    {
	beginTransaction(tabSetId);
    }
    else
    {

	Chain user;
	Chain password;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);

	CegoDbHandler::ResultType res;
	res = pSH->reqStartTransactionOp(tableSet);

	if ( res == CegoDbHandler::DB_OK )
	{
	    _pDBMng->releaseSession(pSH);	    
	}
	else if ( res == CegoDbHandler::DB_ERROR )
	{
	    Chain msg = pSH->getMsg();
	    _pDBMng->releaseSession(pSH);
	    throw Exception(EXLOC, msg); 
	}
    }
}

long CegoDistManager::endDistTransaction( const Chain& tableSet)
{

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

    Chain hostName = _pDBMng->getPrimary(tableSet);
    int tabSetId = _pDBMng->getTabSetId(tableSet);

    Host h;
    if ( hostName.toUpper() == h.getName().toUpper() )
    {

	long numCommitOp=0;
	
	SetT<Chain> tableList;

	getTransactionAffectedTables(tabSetId, tableList);
	
	Chain *pTable;

	pTable = tableList.First();
	while ( pTable )
	{
	    
	    _pDBMng->useObject(tabSetId, *pTable, CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE, _threadId);
	    pTable = tableList.Next();
	}

	try {

	    numCommitOp = commitTransaction(tabSetId);	    
	}
	catch ( Exception e )
	{
	    pTable = tableList.First();
	    while ( pTable )
	    {
		_pDBMng->unuseObject(tabSetId, *pTable, CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE);
		pTable = tableList.Next();
	    }
	}
	pTable = tableList.First();
	while ( pTable )
	{
	    _pDBMng->unuseObject(tabSetId, *pTable, CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE);
	    pTable = tableList.Next();
	}
	
	return numCommitOp;

    }
    else
    {


	Chain user;
	Chain password;

	long numCommitOp=0;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);

	CegoDbHandler::ResultType res;
	res = pSH->reqCommitTransactionOp(tableSet);

	if ( res == CegoDbHandler::DB_OK )
	{
	    _pDBMng->releaseSession(pSH);	    
	}
	else if ( res == CegoDbHandler::DB_ERROR )
	{
	    Chain msg = pSH->getMsg();
	    _pDBMng->releaseSession(pSH);
	    throw Exception(EXLOC, msg); 
	}

	// TODO : numCommitOp still not set up for distributed queries
	return numCommitOp;
    }
}

long CegoDistManager::rollbackDistTransaction(const Chain& tableSet)
{

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

    Chain hostName = _pDBMng->getPrimary(tableSet);
    int tabSetId = _pDBMng->getTabSetId(tableSet);

    Host h;
    if ( hostName.toUpper() == h.getName().toUpper() )
    {

	long numRollbackOp=0;
	
	SetT<Chain> tableList;
	getTransactionAffectedTables(tabSetId, tableList);
	
	Chain *pTable;
	
	pTable = tableList.First();
	while ( pTable )
	{
	    
	    _pDBMng->useObject(tabSetId, *pTable, CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE, _threadId);
	    pTable = tableList.Next();
	}

	try {

	    numRollbackOp = rollbackTransaction(tabSetId);
	}
	catch ( Exception e )
	{
	    pTable = tableList.First();
	    while ( pTable )
	    {
		_pDBMng->unuseObject(tabSetId, *pTable, CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE);
		pTable = tableList.Next();
	    }
	}
	pTable = tableList.First();
	while ( pTable )
	{
	    _pDBMng->unuseObject(tabSetId, *pTable, CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE);
	    pTable = tableList.Next();
	}
	
	return numRollbackOp;

    }
    else
    {

	Chain user;
	Chain password;

	long numRollbackOp=0;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);

	CegoDbHandler::ResultType res;
	res = pSH->reqRollbackTransactionOp(tableSet);

	if ( res == CegoDbHandler::DB_OK )
	{
	    _pDBMng->releaseSession(pSH);	    
	}
	else if ( res == CegoDbHandler::DB_ERROR )
	{
	    Chain msg = pSH->getMsg();
	    _pDBMng->releaseSession(pSH);
	    throw Exception(EXLOC, msg); 
	}

	// TODO : numRollbackOp still not set up for distributed queries
	return numRollbackOp;

    }
}

int CegoDistManager::getDistTid( const Chain& tableSet)
{


    Chain hostName = _pDBMng->getPrimary(tableSet);
    int tabSetId = _pDBMng->getTabSetId(tableSet);

    Host h;
    if ( hostName.toUpper() == h.getName().toUpper() )
    {
	return getLocalTid(tabSetId);
    }
    else
    {
	
	Chain user;
	Chain password;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);

	Chain msg;
	CegoDbHandler::ResultType res;
    
	int tid = 0;
	res = pSH->reqGetTidOp(tableSet);
	
	if ( res == CegoDbHandler::DB_INFO )
	{
	    Chain tidString;
	    pSH->getArgValue(XML_TID_ATTR, tidString);
	    
	    tid = tidString.asInteger();

	    _pDBMng->releaseSession(pSH);	    
	    
	}
	else if ( res == CegoDbHandler::DB_ERROR )
	{
	    Chain msg = pSH->getMsg();
	    _pDBMng->releaseSession(pSH);
	    throw Exception(EXLOC, msg); 
	}
	
	return tid;
    }
}

int CegoDistManager::getLocalTid(int tabSetId)
{
    return getTID(tabSetId);
}

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

long CegoDistManager::getThreadId() const
{
    return _threadId;
}

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

long CegoDistManager::getAllocatedSortArea() const
{
    return _numAllocated;
}

void CegoDistManager::insertDistDataTable(CegoTableObject& oe, ListT<CegoField>& fvl)
{

#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Inserting into global table ") + oe.getName());
#endif

    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); 
    }


    Chain hostName = _pDBMng->getPrimary(oe.getTabSetId());    
    
    Host h;

    if ( hostName.toUpper() == h.getName().toUpper() )
    {
	insertLocalDataTable(oe, fvl);
    }
    else
    {
	
	Chain tableSet =  _pDBMng->getTabSetName(oe.getTabSetId());

	Chain user;
	Chain password;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);
    
	Chain msg;
	CegoDbHandler::ResultType res;
	res = pSH->reqInsertOp(tableSet, oe.getName(), fvl);
	
	if ( res == CegoDbHandler::DB_OK )
	{
	    _pDBMng->releaseSession(pSH);   
	}
	else if ( res == CegoDbHandler::DB_ERROR )
	{
	    Chain msg = pSH->getMsg();
	    _pDBMng->releaseSession(pSH);
	    throw Exception(EXLOC, msg); 
	}
    }
}

void CegoDistManager::insertLocalDataTable(CegoTableObject& oe, ListT<CegoField>& fvl)
{
    _pDBMng->useObject(oe.getTabSetId(), oe.getName(), oe.getType(), CegoDatabaseManager::EXCLUSIVE_WRITE,  _threadId);
    
    try {

	CegoDataPointer dp;
	insertDataTable(oe, fvl, dp, true);
    }
    catch ( Exception e )
    {
	_pDBMng->unuseObject(oe.getTabSetId(), oe.getName(), oe.getType(), CegoDatabaseManager::EXCLUSIVE_WRITE);
	throw e;
    }
    _pDBMng->unuseObject(oe.getTabSetId(), oe.getName(), oe.getType(), CegoDatabaseManager::EXCLUSIVE_WRITE);
}

long CegoDistManager::deleteDistDataTable(CegoTableObject& oe, CegoPredDesc* pPred, CegoProcBlock* pBlock)
{
#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Deleting from global table ") + oe.getName());
#endif

    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); 
    }

    
    Chain hostName = _pDBMng->getPrimary(oe.getTabSetId());

    Host h;

    if ( hostName.toUpper() == h.getName().toUpper() )
    {
	return deleteLocalDataTable(oe, pPred, pBlock);
    }
    else
    {

	Chain tableSet =  _pDBMng->getTabSetName(oe.getTabSetId());

	Chain user;
	Chain password;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);

	pSH->reqDeleteOp(tableSet, oe.getName(), pPred);
	long delCount = pSH->getAffected();
	_pDBMng->releaseSession(pSH);

	return delCount;
    }
}

long CegoDistManager::deleteLocalDataTable(CegoTableObject& oe, CegoPredDesc* pPred, CegoProcBlock* pBlock)
{
    long delCount = 0;

    _pDBMng->useObject(oe.getTabSetId(), oe.getName(), oe.getType(), CegoDatabaseManager::EXCLUSIVE_WRITE, _threadId);
    
    try {

	delCount = deleteDataTable(oe, pPred, pBlock);
    }
    catch ( Exception e)
    {	
	_pDBMng->unuseObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE_WRITE);
	throw e;
    }
    _pDBMng->unuseObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE_WRITE);

    return delCount;
}

long CegoDistManager::updateDistDataTable(CegoTableObject& oe,  
					  CegoPredDesc* pPred, 
					  ListT<CegoField>& updSchema, 
					  ListT<CegoExpr*>& exprList,
					  CegoProcBlock* pBlock)
{

#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Updating global table ") + oe.getName());
#endif

    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); 
    }
    
    Chain hostName = _pDBMng->getPrimary(oe.getTabSetId());

    Host h;

    if ( hostName.toUpper() == h.getName().toUpper() )
    {
	return updateLocalDataTable(oe, pPred, updSchema, exprList, pBlock);
    }
    else
    {
	Chain tableSet =  _pDBMng->getTabSetName(oe.getTabSetId());

	Chain user;
	Chain password;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);
	
	pSH->reqUpdateOp(tableSet, oe.getName(), updSchema, exprList, pPred);
	long updCount = pSH->getAffected();
	_pDBMng->releaseSession(pSH);
	
	return updCount;
    }
}

long CegoDistManager::updateLocalDataTable(CegoTableObject& oe, CegoPredDesc* pPred, ListT<CegoField>& updSchema, ListT<CegoExpr*>& exprList, CegoProcBlock* pBlock)
{
	
    long updCount = 0;
    bool forceTransaction=false;
    if ( getTID(oe.getTabSetId()) == 0 )
    {
	forceTransaction=true;
	beginTransaction(oe.getTabSetId());
    }

    _pDBMng->useObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE_WRITE, _threadId);
    
    try {

	updCount = updateDataTable(oe.getTabSetId(), oe.getTabName(), oe.getTabAlias(), pPred, updSchema, exprList, pBlock);

    }
    catch ( Exception e )
    {       
	_pDBMng->unuseObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE_WRITE);

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

	    try
	    {
		rollbackTransaction(oe.getTabSetId());
	    }
	    catch ( Exception e )
	    {
		_pDBMng->unuseObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE_WRITE);
		throw e;
	    }
	}

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

    if ( forceTransaction )
    {    

	_pDBMng->useObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE, _threadId);

	try
	{
	    commitTransaction(oe.getTabSetId());
	}
	catch ( Exception e )
	{
	    _pDBMng->unuseObject(oe.getTabSetId(), oe.getTabName(), CegoObject::TABLE, CegoDatabaseManager::EXCLUSIVE);
	    throw e;
	}

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

    }

    return updCount;
}


void CegoDistManager::alterDistDataTable(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); 
    }


    Chain hostName = _pDBMng->getPrimary(oe.getTabSetId());
    
    Host h;

    if ( hostName.toUpper() == h.getName().toUpper() )
    {
	alterDataTable(oe.getTabSetId(), oe.getName(), CegoObject::TABLE, alterList);
    }
    else
    {

	Chain tableSet =  _pDBMng->getTabSetName(oe.getTabSetId());

	Chain user;
	Chain password;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);

	pSH->reqAlterTableOp(tableSet, oe.getName(), alterList);
	_pDBMng->releaseSession(pSH);
    }
}

void CegoDistManager::renameDistObject(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

    int 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); 
    }

    Chain hostName = _pDBMng->getPrimary(tabSetId);

    Host h;

    if ( hostName.toUpper() == h.getName().toUpper() )
    {
	renameLocalObject(tabSetId, objName, type, newObjName);
    }
    else
    {

	Chain user;
	Chain password;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);

	pSH->reqRenameOp(tableSet, objName, type, newObjName);
	_pDBMng->releaseSession(pSH);

    }
}

void CegoDistManager::renameLocalObject(int tabSetId, const Chain& objName, CegoObject::ObjectType type,  const Chain& newObjName)
{
    _pDBMng->removeObject(tabSetId, objName, type);
    renameObject(tabSetId, objName, type, newObjName);
    _pDBMng->addObject(tabSetId, newObjName, type);
}

void CegoDistManager::createDistView(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

    int 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); 
    }

    Chain hostName =_pDBMng->getPrimary(tabSetId);    

    Host h;

    if ( hostName.toUpper() == h.getName().toUpper() )
    {
	createLocalView(tabSetId, viewName, schema, viewText);
    }
    else
    {

	Chain user;
	Chain password;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);

	pSH->reqCreateViewOp(tableSet, viewName, schema, viewText);      
	_pDBMng->releaseSession(pSH);
    }
}

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

    createViewObject(vo);
    
    // create log entry
    CegoLogRecord lr;
    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);
    logIt(vo.getTabSetId(), lr);
    free(buf);

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

}

void CegoDistManager::createDistProc(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

    int 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); 
    }

    Chain hostName = _pDBMng->getPrimary(tabSetId);
    
    Host h;

    if ( hostName.toUpper() == h.getName().toUpper() )
    {
	createLocalProc(tabSetId, procName, procText);
    }
    else
    {

	Chain user;
	Chain password;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);

	pSH->reqCreateProcOp(tableSet, procName, procText);
	_pDBMng->releaseSession(pSH);
    }
}

void CegoDistManager::createLocalProc(int tabSetId, const Chain& procName, const Chain& procText)
{
    CegoProcObject po(tabSetId, procName, procText);

    createProcObject(po);

    // create log entry
    CegoLogRecord lr;
    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);
    logIt(po.getTabSetId(), lr);
    free(buf);

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

}

void CegoDistManager::getDistObjectList(const Chain& tableSet, CegoObject::ObjectType type, ListT<Chain> &objList)
{

#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Getting global object list in tableset ") + tableSet);
#endif

    int tabSetId = _pDBMng->getTabSetId(tableSet);    
    Chain hostName = _pDBMng->getPrimary(tabSetId);

    Host h;

    if ( hostName.toUpper() == h.getName().toUpper() )
    {
	getLocalObjectList(tabSetId, type, objList);
    }
    else
    {
	
	Chain user;
	Chain password;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);

	CegoDbHandler::ResultType res;
    
	res = pSH->reqGetObjectListOp(tabSetId, type);

	if ( res == CegoDbHandler::DB_INFO )
	{
	    pSH->getObjectList(objList);
	    _pDBMng->releaseSession(pSH);	    
	    
	}
	else if ( res == CegoDbHandler::DB_ERROR )
	{
	    Chain msg = pSH->getMsg();
	    _pDBMng->releaseSession(pSH);
	    throw Exception(EXLOC, msg); 
	}
    }
}

void CegoDistManager::getLocalObjectList(int tabSetId, CegoObject::ObjectType type, ListT<Chain> &objList)
{
    getObjectList(tabSetId, type, objList);
}

void CegoDistManager::getDistObjectByTableList(const Chain& tableSet, 
					       const Chain& tabName,
					       ListT<CegoTableObject>& idxList,
					       ListT<CegoBTreeObject>& btreeList,
					       ListT<CegoKeyObject>& keyList,
					       ListT<CegoCheckObject>& checkList, bool ignoreInvalid)
{
#ifdef CGDEBUG
    _pDBMng->log(_modId, Logger::DEBUG, Chain("Getting global object list by table ") + tabName + Chain(" in tableset ") + tableSet);
#endif

    int tabSetId = _pDBMng->getTabSetId(tableSet);    
    Chain hostName = _pDBMng->getPrimary(tabSetId);

    Host h;

    if ( hostName.toUpper() == h.getName().toUpper() )
    {
	getObjectListByTable(tabSetId, tabName, idxList, btreeList, keyList, checkList, ignoreInvalid);
    }
    else
    {

	Chain user;
	Chain password;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);

	CegoDbHandler::ResultType res;

	res = pSH->reqGetObjectByTableListOp(tableSet, tabName);

	if ( res == CegoDbHandler::DB_INFO )
	{
	    pSH->getObjectByTableList(idxList, keyList, checkList);
	    _pDBMng->releaseSession(pSH);	    
	    
	}
	else if ( res == CegoDbHandler::DB_ERROR )
	{
	    Chain msg = pSH->getMsg();
	    _pDBMng->releaseSession(pSH);
	    throw Exception(EXLOC, msg); 
	}
    }
}

int CegoDistManager::getDistPageCount(const Chain& tableSet, const Chain& tabName, CegoObject::ObjectType type)
{

    int tabSetId = _pDBMng->getTabSetId(tableSet);    
    Chain hostName = _pDBMng->getPrimary(tabSetId);

    Host h;

    if ( hostName.toUpper() == h.getName().toUpper() )
    {
	return getPageCount(tabSetId, tabName, type);
    }
    else
    {

	Chain user;
	Chain password;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);

	CegoDbHandler::ResultType res;

	res = pSH->reqGetPageCount(tableSet, tabName, type);

	int pageCount = 0;

	if ( res == CegoDbHandler::DB_INFO )
	{
	    pSH->getPageCount(pageCount);
	    _pDBMng->releaseSession(pSH);	    
	    
	}
	else if ( res == CegoDbHandler::DB_ERROR )
	{
	    Chain msg = pSH->getMsg();
	    _pDBMng->releaseSession(pSH);
	    throw Exception(EXLOC, msg); 
	}

	return pageCount;

    }
}

CegoAttrCond::IndexMatch CegoDistManager::distIndexExists(int tabSetId, const Chain& tableName, CegoAttrCond& ac)
{    
    ListT<CegoTableObject> idxList;
    ListT<CegoBTreeObject> btreeList;
    ListT<CegoKeyObject> keyList;
    ListT<CegoCheckObject> checkList;

    Host h;
    
    Chain hostName = _pDBMng->getPrimary(tabSetId);    

    if ( hostName.toUpper() == h.getName().toUpper() )
    {
	getObjectListByTable(tabSetId, tableName, idxList, btreeList, keyList, checkList);

	CegoAttrCond::IndexMatch idxMatch = CegoAttrCond::INAPP;

	CegoTableObject *pIO = idxList.First();
	while ( pIO )
	{
	    CegoTableObject idx;
	    
	    getObject(tabSetId, pIO->getName(), pIO->getType(), idx);
	    
	    CegoAttrCond::IndexMatch nextMatch = ac.checkIndex(idx.getSchema());
	    
	    if ( nextMatch == CegoAttrCond::FULL )
		return nextMatch;
	    if  ( idxMatch == CegoAttrCond::INAPP && nextMatch == CegoAttrCond::PART )
		idxMatch = CegoAttrCond::PART;
	    
	    pIO = idxList.Next();
	}
	return idxMatch;
    }
    else
    {

	Chain user;
	Chain password;

	Chain tableSet =  _pDBMng->getTabSetName(tabSetId);

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);

	CegoDbHandler::ResultType res;

	res = pSH->reqGetObjectByTableListOp(tableSet, tableName);

	if ( res == CegoDbHandler::DB_INFO )
	{
	    pSH->getObjectByTableList(idxList, keyList, checkList);	    
	}
	else if ( res == CegoDbHandler::DB_ERROR )
	{
	    Chain msg = pSH->getMsg();
	    _pDBMng->releaseSession(pSH);
	    throw Exception(EXLOC, msg); 
	}

	CegoAttrCond::IndexMatch idxMatch = CegoAttrCond::INAPP;

	CegoTableObject *pIO = idxList.First();
	while ( pIO )
	{
	    CegoTableObject idx;

	    res = pSH->reqObjectInfoOp(tabSetId, pIO->getName(), pIO->getType());
	    
	    if ( res == CegoDbHandler::DB_INFO )
	    {
		idx.putElement( pSH->getObjElement() );
		idx.setLocal(false);
		

		CegoAttrCond::IndexMatch nextMatch = ac.checkIndex(idx.getSchema());
		
		if ( nextMatch == CegoAttrCond::FULL )
		{
		    _pDBMng->releaseSession(pSH);
		    return nextMatch;
		}
		if  ( idxMatch == CegoAttrCond::INAPP && nextMatch == CegoAttrCond::PART )
		    idxMatch = CegoAttrCond::PART;
		
	    }
	    else if ( res == CegoDbHandler::DB_ERROR )
	    {
		Chain msg = pSH->getMsg();
		_pDBMng->releaseSession(pSH);
		throw Exception(EXLOC, msg); 
	    }
	    pIO = idxList.Next();
	}
	_pDBMng->releaseSession(pSH);
	return idxMatch;
    }
}

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

void CegoDistManager::syncDistTableSet(const Chain& tableSet, const Chain& msg, const Chain& escCmd, int timeout)
{

    int tabSetId = _pDBMng->getTabSetId(tableSet);    
    Chain hostName =_pDBMng->getPrimary(tabSetId);
    Host h;

    if ( hostName.toUpper() == h.getName().toUpper() )
    {
	syncTableSet(tableSet, msg, escCmd, timeout);
    }
    else
    {

	Chain user;
	Chain password;

	getActiveUser(tableSet, user, password);
	
	CegoDistDbHandler *pSH = _pDBMng->allocateSession(hostName, tableSet, user, password);

	pSH->reqSyncOp(tableSet, escCmd, timeout);
	_pDBMng->releaseSession(pSH);

    }
}

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

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

void CegoDistManager::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& CegoDistManager::getUser() const
{
    return _authUser;
}

void CegoDistManager::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);

}

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

    int tabSetId = _pDBMng->getTabSetId(tableSet);

    Element *pVerification = new Element(XML_VERIFICATION_ELEMENT);
    
    int errorCount = 0;
    
    ListT<CegoTableObject> idxList;
    ListT<CegoBTreeObject> btreeList;
    ListT<CegoKeyObject> keyList;
    ListT<CegoCheckObject> checkList;

    getObjectListByTable(tabSetId, tableName, idxList, btreeList, keyList, checkList, false);
	
    CegoTableObject oe;
    getObject(tabSetId, tableName, CegoObject::TABLE, oe);
    	
    CegoTableCursor tc(this, tabSetId, tableName);
    ListT<CegoField> fl = oe.getSchema();
    CegoDataPointer dp;
    long tabCount = 0;

    if ( tc.getFirst(fl, dp) )
    {
	tabCount++;
	while ( tc.getNext(fl, dp) )
	{
	    tabCount++;
	}
    }

    // verify keys
    bool keyCheck = true;
    CegoKeyObject *pKey = keyList.First();
    while ( pKey ) 
    {
	checkKey(pKey);
	pKey = keyList.Next();	    
    }
    
    
    if ( keyCheck == false )
    {
	errorCount++;
	Chain tableStatus = Chain("Key constraint violation");
	Element *pTableCheck = new Element(XML_CHECK_ELEMENT);
	pTableCheck->setAttribute(XML_TYPE_ATTR, Chain("Table"));
	pTableCheck->setAttribute(XML_NAME_ATTR, tableName);
	pTableCheck->setAttribute(XML_VALUE_ATTR, tableStatus);
	pVerification->addContent(pTableCheck);	    
    }
    
    // verify indexes
    CegoTableObject *pIdx = idxList.First();
    while ( pIdx ) 
    {

	if ( pIdx->isValid() )
	{
	    CegoAVLIndexManager idxMng(this);
	    char c = idxMng.checkIndex(tabSetId, pIdx->getName(), pIdx->getType());
	    
	    if ( c < 0 )
	    {
		errorCount++;
		Chain tableStatus = Chain("Index ") + pIdx->getName() + Chain(" due to height corrupted ");
		Element *pTableCheck = new Element(XML_CHECK_ELEMENT);
		pTableCheck->setAttribute(XML_TYPE_ATTR, Chain("Table"));
		pTableCheck->setAttribute(XML_NAME_ATTR, tableName);
		pTableCheck->setAttribute(XML_VALUE_ATTR, tableStatus);
		pVerification->addContent(pTableCheck);      
	    }
	    
	    CegoAVLIndexCursor ic(this, tabSetId, pIdx->getName(), pIdx->getType(), 0, false, false);
	    
	    ListT<CegoField> fl = oe.getSchema();
	    CegoDataPointer dp;
	    long idxCount = 0;
	    if ( ic.getFirst(fl, dp) )
	    {
		idxCount++;
		while ( ic.getNext(fl, dp) )
		    idxCount++;
	    }
	    if ( tabCount != idxCount )
	    {
		errorCount++;
		Chain tableStatus = Chain("Index ") + pIdx->getName() + Chain(" due to row count corrupted");
		Element *pTableCheck = new Element(XML_CHECK_ELEMENT);
		pTableCheck->setAttribute(XML_TYPE_ATTR, Chain("Table"));
		pTableCheck->setAttribute(XML_NAME_ATTR, tableName);
		pTableCheck->setAttribute(XML_VALUE_ATTR, tableStatus);
		pVerification->addContent(pTableCheck);
	    }
	}
	else
	{
	    errorCount++;
	    Chain tableStatus = Chain("Index ") + pIdx->getName() + Chain(" not valid");
	    Element *pTableCheck = new Element(XML_CHECK_ELEMENT);
	    pTableCheck->setAttribute(XML_TYPE_ATTR, Chain("Table"));
	    pTableCheck->setAttribute(XML_NAME_ATTR, tableName);
	    pTableCheck->setAttribute(XML_VALUE_ATTR, tableStatus);
	    pVerification->addContent(pTableCheck);	    
	}
	
	pIdx = idxList.Next();
    }
    
    if ( errorCount == 0 )
    {
	Chain tableStatus("ok");
	Element *pTableCheck = new Element(XML_CHECK_ELEMENT);
	pTableCheck->setAttribute(XML_TYPE_ATTR, Chain("Table"));
	pTableCheck->setAttribute(XML_NAME_ATTR, tableName);
	pTableCheck->setAttribute(XML_VALUE_ATTR, tableStatus);
	pVerification->addContent(pTableCheck);			      
    }
    
    return pVerification;
    
}


Element* CegoDistManager::verifyView(const Chain& tableSet, const Chain& viewName)
{
    int tabSetId = _pDBMng->getTabSetId(tableSet);    
    Element *pVerification = new Element(XML_VERIFICATION_ELEMENT);
    
    CegoViewObject vo;
    getObject(tabSetId, viewName, CegoObject::VIEW, vo);
    
    Chain loadString = Chain("load ") + vo.getViewStmt();
    
    CegoAction *pPA = new CegoAction(this);
    pPA->setTableSet(tableSet);
    pPA->setCommandChain(loadString);
    pPA->parse();
    
    delete pPA;
    
    Chain viewStatus("ok");	
    Element *pViewCheck = new Element(XML_CHECK_ELEMENT);
    pViewCheck->setAttribute(XML_TYPE_ATTR, Chain("View"));
    pViewCheck->setAttribute(XML_NAME_ATTR, viewName);
    pViewCheck->setAttribute(XML_VALUE_ATTR, viewStatus);
    pVerification->addContent(pViewCheck);			      
    
    return pVerification;

}

Element* CegoDistManager::verifyProcedure(const Chain& tableSet, const Chain& procName)
{

    int tabSetId = _pDBMng->getTabSetId(tableSet);    
    Element *pVerification = new Element(XML_VERIFICATION_ELEMENT);
    
    CegoProcObject po;
    getObject(tabSetId, procName, CegoObject::PROCEDURE, po);
	
    Chain loadString = Chain("load ") + po.getProcText();
    
    CegoAction *pPA = new CegoAction(this);
    pPA->setTableSet(tableSet);
    pPA->setCommandChain(loadString);
    pPA->parse();
    
    delete pPA;
    
    Chain procStatus("ok");	
    Element *pProcCheck = new Element(XML_CHECK_ELEMENT);
    pProcCheck->setAttribute(XML_TYPE_ATTR, Chain("Procedure"));
    pProcCheck->setAttribute(XML_NAME_ATTR, procName);
    pProcCheck->setAttribute(XML_VALUE_ATTR, procStatus);
    pVerification->addContent(pProcCheck);			      
    
    return pVerification;
}

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

    int tabSetId = _pDBMng->getTabSetId(tableSet);

    Element *pCorrection = new Element(XML_CORRECTION_ELEMENT);
    
    int errorCount = 0;
    
    ListT<CegoTableObject> idxList;
    ListT<CegoBTreeObject> btreeList;
    ListT<CegoKeyObject> keyList;
    ListT<CegoCheckObject> checkList;

    getObjectListByTable(tabSetId, tableName, idxList, btreeList, keyList, checkList, false);
	
    CegoTableObject oe;
    getObject(tabSetId, tableName, CegoObject::TABLE, oe);
    	
    CegoTableCursor tc(this, tabSetId, tableName);
    ListT<CegoField> fl = oe.getSchema();
    CegoDataPointer dp;
    long tabCount = 0;

    if ( tc.getFirst(fl, dp) )
    {
	tabCount++;
	while ( tc.getNext(fl, dp) )
	{
	    tabCount++;
	}
    }

    
    // correct indexes
    CegoTableObject *pIdx = idxList.First();
    while ( pIdx ) 
    {

	if ( pIdx->isValid() == false )
	{
	    errorCount++;

	    dropIndex(tabSetId, pIdx->getName());
	    createIndexTable(tabSetId, pIdx->getName(), pIdx->getTabName(), pIdx->getSchema(), pIdx->getType());

	    Chain tableStatus = Chain("Index ") + pIdx->getName() + Chain(" was corrected");
	    Element *pTableCheck = new Element(XML_CHECK_ELEMENT);
	    pTableCheck->setAttribute(XML_TYPE_ATTR, Chain("Table"));
	    pTableCheck->setAttribute(XML_NAME_ATTR, tableName);
	    pTableCheck->setAttribute(XML_VALUE_ATTR, tableStatus);
	    pCorrection->addContent(pTableCheck);	    
	}
	
	pIdx = idxList.Next();
    }
    
    if ( errorCount == 0 )
    {
	Chain tableStatus("ok");
	Element *pTableCheck = new Element(XML_CHECK_ELEMENT);
	pTableCheck->setAttribute(XML_TYPE_ATTR, Chain("Table"));
	pTableCheck->setAttribute(XML_NAME_ATTR, tableName);
	pTableCheck->setAttribute(XML_VALUE_ATTR, tableStatus);
	pCorrection->addContent(pTableCheck);			      
    }
    
    return pCorrection;
    
}


bool CegoDistManager::checkKey(CegoKeyObject *pKey)
{

    CegoField *pRF = pKey->getKeySchema().First();
    if ( pRF )
    {
	
	CegoTableCursor rtc(this, pKey->getTabSetId(), pKey->getTabName());	
	
	ListT<CegoField> rfl = pKey->getKeySchema();
		
	CegoDataPointer rdp;
	
	bool moreRefTuple = rtc.getFirst(rfl, rdp);
	
	while ( moreRefTuple ) 
	{

	    CegoTableCursor tc(this, pKey->getTabSetId(), pKey->getRefTable());
	    
	    CegoField *pF = rfl.First();
	    if ( pF )
	    {
		
		CegoAttrCond ac;
		ac.add(CegoAttrComp(pF->getAttrName(), EQUAL, pF->getValue()));
 
		ListT<CegoField> fl;
		
		if ( tc.setup(ac) == false )
		{
		    CegoTableObject oe;
		    getObject(pKey->getTabSetId(), pKey->getTabName(), CegoObject::TABLE, oe);
		    fl = oe.getSchema();
		}
		else
		{
		    tc.getIdxSchema(fl);
		}
		
		
		CegoDataPointer dp;
		bool moreTuple = tc.getFirst(fl, dp);
		while ( moreTuple ) 
		{
		    bool isMatch;
		    CegoField *pCF = fl.First();
		    while ( pCF )
		    {
			isMatch = true;
			CegoField *pD = rfl.Find(*pCF);
			if ( pD )
			{
			    if ( (CegoFieldValue)pD->getValue() != (CegoFieldValue)pCF->getValue() )
			    {
				isMatch=false;
			    }
			}
			pCF = fl.Next();
		    }
		}
	    }
	    moreRefTuple = rtc.getNext(rfl, rdp);
	}
    }
    return true;
}

void CegoDistManager::getObjectDesc(const Chain& tableSet, const Chain& objName, CegoObject::ObjectType type, 
				    ListT<CegoField>& schema, ListT< ListT<CegoFieldValue> > &fa)
{
    
    switch ( type )
    {
    case CegoObject::SYSTEM:
    case CegoObject::TABLE:
    {
	CegoTableObject to;
	getDistObject(tableSet, objName, type, to);
	
	int maxAttrLen=10;
	CegoField *pF = to.getSchema().First();
	while ( pF )
	{
	    if ( 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("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;	    
	    CegoTypeConverter tc;
	   
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, pF->getAttrName()));
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, tc.getTypeString(pF->getType())));
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, Chain(pF->getLength())));
	    
	    // UNDER INVESTIGATION
	    // fvl.Insert(CegoFieldValue(VARCHAR_TYPE, pF->getValue().valAsChain(false)));
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, pF->getValue().toChain()));
	    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::INDEX:
    case CegoObject::UINDEX:
    case CegoObject::PINDEX:
    {
	CegoTableObject io;
	getDistObject(tableSet, objName, type, io);
	
	int maxAttrLen=10;
	CegoField *pF = io.getSchema().First();
	while ( pF )
	{
	    if ( pF->getAttrName().length() > maxAttrLen )
		maxAttrLen = pF->getAttrName().length();
	    pF = io.getSchema().Next();
	}

	int maxTabLen=10;	
	if ( 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;	    
	    CegoTypeConverter tc;
	   
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, pF->getAttrName()));
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, io.getTabName()));
	    
	    if ( io.getType() == CegoObject::INDEX) 
		fvl.Insert(CegoFieldValue(VARCHAR_TYPE, XML_INDEX_VALUE));
	    else if ( io.getType() == CegoObject::PINDEX)
		fvl.Insert(CegoFieldValue(VARCHAR_TYPE, XML_PINDEX_VALUE));
	    else if ( io.getType() == CegoObject::UINDEX)
		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;
	getDistObject(tableSet, objName, type, bto);
	
	int maxAttrLen=10;
	CegoField *pF = bto.getSchema().First();
	while ( pF )
	{
	    if ( pF->getAttrName().length() > maxAttrLen )
		maxAttrLen = pF->getAttrName().length();
	    pF = bto.getSchema().Next();
	}

	int maxTabLen=10;	
	if ( 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;	    
	    CegoTypeConverter tc;
	   
	    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;
	getDistObject(tableSet, objName, type, vo);

	int maxAttrLen=10;
	CegoField *pF = vo.getSchema().First();
	while ( pF )
	{
	    if ( 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));

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

	    fa.Insert(fvl);

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

	int tabSetId = getDBMng()->getTabSetId(tableSet);

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

	CegoProcedure* pProc = getCompProcedure(tabSetId, objName);

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

	int maxAttrLen=10;
	CegoProcVar *pArg = argList.First();
	while ( pArg )
	{
	    if ( 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("INOUT"), VARCHAR_TYPE, 10));
	
	pArg = argList.First();
	while ( pArg )
	{
	    ListT<CegoFieldValue> fvl;	    
	    CegoTypeConverter tc;

	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, pArg->getName()));
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, tc.getTypeString(pArg->getType())));	  
	    fvl.Insert(CegoFieldValue(VARCHAR_TYPE, Chain(pArg->getLength())));
		       
	    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;
	getDistObject(tableSet, objName, type, ko);
	
	int maxTabLen=10;
	if ( objName.length() > maxTabLen )
	    maxTabLen = objName.length();
	
	int maxAttrLen=10;
	CegoField *pK = ko.getKeySchema().First();
	while ( pK )
	{
	    if ( pK->getAttrName().length() > maxAttrLen )
		maxAttrLen = pK->getAttrName().length();
	    
	    pK = ko.getKeySchema().Next();
	}
	CegoField *pR = ko.getRefSchema().First();
	while ( pR )
	{
	    if ( 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;	    
	    CegoTypeConverter tc;
	    
	    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;	    
	    CegoTypeConverter tc;
	    
	    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;
	getDistObject(tableSet, objName, type, co);
	
	int maxTabLen=10;
	if ( objName.length() > maxTabLen )
	    maxTabLen = objName.length();
	
	int 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()));

	fa.Insert(fvl);

	break;

    }
    case CegoObject::RBSEG:
    case CegoObject::JOIN:
    case CegoObject::UNDEFINED:	
    {
	throw Exception(EXLOC, Chain("Cannot get description for object type"));
    }
    }
}

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

void CegoDistManager::reloadView(int tabSetId, const Chain& viewName)
{
    CegoViewObject vo;
    getObject(tabSetId, viewName, CegoObject::VIEW, vo);
    
    Chain loadString = Chain("load ") + vo.getViewStmt();

    _pDBMng->log(_modId, Logger::NOTICE, Chain("View ") + viewName + Chain(" is reloaded"));

    CegoAction* pPA = new CegoAction(this);
    
    try
    {	
	Chain tableSet = _pDBMng->getTabSetName(tabSetId);
	pPA->setTableSet(tableSet);
	pPA->setCommandChain(loadString);
	pPA->parse();
	
	CegoSelect* pSelect = pPA->getSelect();
	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() + Chain(";");
	    createLocalView( tabSetId, viewName, schema, viewStmt);
	    
	    _pDBMng->log(_modId, Logger::NOTICE, Chain("View ") + viewName + Chain(" validated sucessful"));

	}
	
	delete pPA;
    }
    catch ( Exception e )
    {
	delete pPA;
	Chain msg = Chain("Cannot load view ") + viewName; 
	throw Exception(EXLOC, msg, e);
    }
}

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

void CegoDistManager::reloadProcedure(int tabSetId, const Chain& procName)
{

    CegoProcObject po;
    getObject(tabSetId, procName, CegoObject::PROCEDURE, po);
    
    Chain loadString = Chain("load ") + po.getProcText();

    _pDBMng->log(_modId, Logger::NOTICE, Chain("Procedure ") + procName + Chain(" is reloaded"));        

    CegoAction* pPA = new CegoAction(this);
    
    try 
    {
	Chain tableSet = _pDBMng->getTabSetName(tabSetId);

	pPA->setTableSet(tableSet);
	pPA->setCommandChain(loadString);
	pPA->parse();
	
	CegoProcedure* pProc = pPA->getProcedure();
	addCompProcedure(tabSetId, pProc);

	delete pPA;
    }
    catch ( Exception e )
    {
	delete pPA;
	Chain msg = Chain("Cannot load procedure ") + procName; 
	throw Exception(EXLOC, msg, e);
    }
}


