///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoQuery.cc
// ------------
// Cego query implementation         
//     
// Design and Implementation by Bjoern Lemke
//     
// (C)opyright 2000-2025 Bjoern Lemke
//
// IMPLEMENTATION MODULE
//
// Class: CegoQuery
// 
// Description: All modifying queries
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

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

#include "CegoQueryException.h"
#include "CegoOutput.h"
#include "CegoQuery.h"
#include "CegoDatabaseFormater.h"

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

CegoQuery::CegoQuery(CegoQueryManager* pGTM, const Chain& tableSet, CegoQuery::TransactionOp to)
{
    if ( to == CegoQuery::START )
	_mode = START_QUERY;
    else if ( to == CegoQuery::COMMIT )
	_mode = COMMIT_QUERY;
    else if ( to == CegoQuery::ROLLBACK )
	_mode = ROLLBACK_QUERY;
    
    _pGTM = pGTM;
    _tableSet = tableSet;
    _pPred = 0;
    _pSelect = 0;
}

CegoQuery::CegoQuery(CegoQueryManager* pGTM, const Chain& tableSet,
		     const Chain& tableName,
		     const ListT<CegoField>& schema,
		     const ListT<ListT<CegoExpr*> >& exprListArray)
{
    _mode = INSERT_QUERY;
    _pGTM = pGTM;
    _tableName = tableName;
    _tableSet = tableSet;
    _schema = schema;
    _pSelect = 0;
    _exprListArray = exprListArray;
    _pPred = 0;
}

CegoQuery::CegoQuery(CegoQueryManager* pGTM, const Chain& tableSet,
		     const Chain& tableName,
		     const ListT<CegoField>& schema,
		     CegoSelect *pSelect)
{
    _mode = INSERTBYSELECT_QUERY;
    _pGTM = pGTM;
    _tableName = tableName;
    _tableSet = tableSet;
    _schema = schema;
    _pSelect = pSelect;
    _pPred = 0;
}

CegoQuery::CegoQuery(CegoQueryManager* pGTM, const Chain& tableSet,
		     const Chain& tableName,
		     const Chain& tableAlias,
		     CegoPredicate* pPred)
{
    _mode = DELETE_QUERY;
    _pGTM = pGTM;
    _tableName = tableName;
    _tableAlias = tableAlias;
    _tableSet = tableSet;
    _pPred = pPred;
    _pSelect = 0;    
}

CegoQuery::CegoQuery(CegoQueryManager* pGTM, const Chain& tableSet,
		     const Chain& tableName,
		     const Chain& tableAlias,
		     CegoPredicate* pPred,
		     ListT<CegoField>& updSchema,
		     const ListT<CegoExpr*>& updList,
		     const ListT<CegoReturnVar*> retVarList,
		     bool returnOnFirst)
{
    _mode = UPDATE_QUERY;
    _pGTM = pGTM;
    _tableName = tableName;
    _tableAlias = tableAlias;
    _tableSet = tableSet;
    _pPred = pPred;
    _schema = updSchema;
    _pSelect = 0;
    _updList = updList;
    _retVarList = retVarList;
    _returnOnFirst = returnOnFirst;
}

CegoQuery::CegoQuery(CegoQueryManager* pGTM, const Chain& tableSet,
		     const Chain& tableName,
		     bool doLock)
{
    if ( doLock )
	_mode = LOCK_QUERY;
    else
	_mode = UNLOCK_QUERY;
    _pGTM = pGTM;
    _tableName = tableName;
    _tableSet = tableSet;
    _pPred = 0;
    _pSelect = 0;
}

CegoQuery::CegoQuery(CegoQueryManager* pGTM, const Chain& tableSet,
		     const Chain& tableName,
		     const ListT<CegoAlterDesc>& alterList)
{
    _mode = ALTER_QUERY;
    _pGTM = pGTM;
    _tableName = tableName;
    _tableSet = tableSet;
    _alterList = alterList;
    _pPred = 0;
    _pSelect = 0;
}

CegoQuery::CegoQuery(CegoQueryManager* pGTM, const Chain& tableSet,
		     const Chain& objName,
		     CegoObject::ObjectType objType,
		     const Chain& newObjName )
{
    _mode = RENAME_QUERY;
    _pGTM = pGTM;
    _tableSet = tableSet;
    _objName = objName;
    _objType = objType;
    _newObjName = newObjName;
    _pPred = 0;
    _pSelect = 0;
}

CegoQuery::~CegoQuery()
{   
    CegoExpr **pExpr = _updList.First();
    while ( pExpr )
    {
	delete *pExpr;
	pExpr = _updList.Next();
    }

    ListT<CegoExpr*> *pExprList = _exprListArray.First();
    while ( pExprList )
    {
	CegoExpr **pExpr = pExprList->First();
	while ( pExpr )
	{
	    delete *pExpr;
	    pExpr = pExprList->Next();
	}
	pExprList = _exprListArray.Next();
    }

    if ( _pPred )
	delete _pPred;
    if ( _pSelect )
	delete _pSelect;
    
}


Chain CegoQuery::execute(CegoProcBlock *pBlock)
{   
    if ( _pGTM == 0 )
	throw Exception(EXLOC, "No valid table manager set up");

    _affCount = 0;
    
    switch ( _mode )
    {
    case START_QUERY:
    {
	try
	{
	    _pGTM->startTransaction(_tableSet);
	}
	catch ( Exception e )
	{
	    throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Cannot start transaction"), e);
	}
	return Chain("Transaction started");
    }
    case COMMIT_QUERY:
    {
	long opCount = 0;
	try
	{
	    opCount = _pGTM->endTransaction(_tableSet);
	}
	catch ( Exception e )
	{
	    throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Cannot commit transaction"), e);    
	}
	Chain msg = Chain(opCount) + Chain(" operations committed");
	return msg;
    }
    case ROLLBACK_QUERY:
    {
	long opCount = 0;
	try
	{
	    opCount = _pGTM->rollbackTransaction(_tableSet);
	}
	catch ( Exception e )
	{
	    throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Cannot rollback transaction"), e);    
	}
	Chain msg = Chain(opCount) + Chain(" operations rollbacked");
	return msg;
    }	
    case LOCK_QUERY:
    {
	try
	{
	    unsigned tabSetId = _pGTM->getDBMng()->getTabSetId(_tableSet);    
	    _pGTM->lockTable(tabSetId, _tableName);
	}
	catch ( Exception e )
	{
	    throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Cannot lock table"), e);  
	}
	Chain msg = Chain("Table ") + _tableName + Chain(" locked");
	return msg;
    }	
    case UNLOCK_QUERY:
    {
	try
	{
	    unsigned tabSetId = _pGTM->getDBMng()->getTabSetId(_tableSet);
	    _pGTM->unlockTable(tabSetId, _tableName);
	}
	catch ( Exception e )
	{
	    throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Cannot unlock table"), e);    
	}
	Chain msg = Chain("Table ") + _tableName + Chain(" unlocked");
	return msg;
    }	
    case INSERT_QUERY:
    {	
	if ( _pGTM->getAutoCommit() == false )
	{
	    if ( _pGTM->getTid(_tableSet) == 0 )
	    {
		_pGTM->startTransaction(_tableSet);
	    }
	}

	CegoTableObject oe;
	ListT<CegoField> execSchema = _schema;
	ListT<CegoExpr*> addExprList;
	
	try
	{
	    unsigned tabSetId = _pGTM->getDBMng()->getTabSetId(_tableSet);
	    if ( _pGTM->objectExists(tabSetId, _tableName, CegoObject::ALIAS ))
	    {
		CegoAliasObject ao;
		_pGTM->getObject(tabSetId, _tableName, CegoObject::ALIAS, ao);

		// get table object for alias
		_pGTM->getObject(tabSetId, ao.getTabName(), CegoObject::TABLE, oe);

		if (  execSchema.isEmpty() )
		{
		    // set alias schema to original table schema
		    ao.setSchema(oe.getSchema());		    
		    // modify schema with alias definitons
		    ao.mapSchema();
		    // now we can setup target schema
		    execSchema = ao.getSchema();
		}
						
		CegoQueryHelper::mapAliasSchema(execSchema, ao.getAliasList());
	    }
	    else
	    {
		_pGTM->getObject(tabSetId, _tableName, CegoObject::TABLE, oe);
	    }
	}
	catch ( Exception e )
	{
	    throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Cannot map schema for insert"), e);    
	}
	
	if (  execSchema.isEmpty() )
	{   
	    execSchema = oe.getSchema();
	}
	else
	{
	    /* complete missing attributes in schema */
	    ListT<CegoField> checkSchema = oe.getSchema();

	    CegoField *pF = checkSchema.First();
	    while ( pF )
	    {	
		CegoField *pCF = execSchema.Find(*pF);
		if ( pCF == 0  )
		{
		    // cout << "Checking for default value on " << pF->getAttrName() << endl;
		    if ( pF->getValue().getValue() )
		    {
			execSchema.Insert( *pF );

			CegoFieldValue fv = pF->getValue();
			CegoExpr* pExpr = new CegoExpr( new CegoTerm( new CegoFactor( fv )));

			addExprList.Insert(pExpr);
		    }
		    else if ( pF->isNullable() )
		    {
			execSchema.Insert( *pF );

			CegoFieldValue fv;
			CegoExpr* pExpr = new CegoExpr( new CegoTerm( new CegoFactor( fv )));

			addExprList.Insert(pExpr);
		    }
		    else
		    {
			throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Attribute ") + pF->getAttrName() + " not nullable"); 
		    }
		}
		else
		{
		    pCF->setType(pF->getType());
		    pCF->setLength(pF->getLength());
		    pCF->setDim(pF->getDim());
		}
		pF = checkSchema.Next();
	    }
	    pF = execSchema.First();
	    while ( pF )
	    {
		CegoField *pUF = oe.getSchema().Find(*pF);
		if ( pUF )
		{
		    pF->setValue(pUF->getValue());
		    pF->setNullable(pUF->isNullable());
		}
		else
		{
		    throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Unknown attribute ") + pF->getAttrName() );
		}
		
		pF = execSchema.Next();
	    }
	}

	try
	{
	    ListT< ListT<CegoField> > fva;
	    
	    ListT<CegoExpr*> *pExprList = _exprListArray.First();
	    while ( pExprList )
	    {	   
		CegoField* pFV = execSchema.First();
		CegoExpr** pExpr = pExprList->First();
			
		while ( pFV && pExpr)
		{	    
		    // treat trigger value list

		    ListT<CegoField>* fl[2];
		    fl[0] = pBlock->getTriggerValueList();
		    fl[1] = 0;

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

		   
		    try
		    {
			CegoQueryHelper::prepareFieldValue(pFV, fv, _pGTM, oe.getTabSetId());
		    }
		    catch ( Exception e )
		    {
			Chain msg;
			e.pop(msg);
			throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain(msg));
		    }
		    		    

		    pFV->setValue(fv);

		    pFV = execSchema.Next();
		    pExpr = pExprList->Next();
		}

		pExpr = addExprList.First();
		while ( pFV && pExpr)
		{	    
		    // treat trigger value list
		    
		    ListT<CegoField>* fl[2];
		    fl[0] = pBlock->getTriggerValueList();
		    fl[1] = 0;

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

		    try
		    {
			CegoQueryHelper::prepareFieldValue(pFV, fv, _pGTM, oe.getTabSetId());
		    }
		    catch ( Exception e )
		    {
			Chain msg;
			e.pop(msg);			
			throw CegoQueryException(COREOP_EXCEP, EXLOC, msg);
		    }

		    pFV->setValue(fv);

		    pFV = execSchema.Next();
		    pExpr = addExprList.Next();		    
		}
		
		if ( pFV || pExpr )
		{		    
		    throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Mismatched argument count for value list"));
		}	    

		fva.Insert(execSchema);
		pExprList = _exprListArray.Next();
	    }
	    
	    try
	    {				
		_pGTM->insertQueryTable(oe, fva);

		_pGTM->getDBMng()->cleanCache( oe.getTabSetId(), CegoObject::TABLE, oe.getTabName());
		
		_affCount+=fva.Size();

		// clean addExprList
		CegoExpr **pExpr = addExprList.First();
		while ( pExpr )
		{
		    delete *pExpr;
		    pExpr = addExprList.Next();
		}		
	    }
	    catch ( Exception e )
	    {
		CegoExpr **pExpr = addExprList.First();
		while ( pExpr )
		{
		    delete *pExpr;
		    pExpr = addExprList.Next();
		}
	    		
		throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Cannot insert tuple data"), e);
	    }	       
	}
	catch ( CegoQueryException e )
	{
	    
	    // clean clobs and blobs
	    
	    unsigned tabSetId = _pGTM->getDBMng()->getTabSetId(_tableSet);
	    
	    CegoField *pF = execSchema.First();
	    
	    while ( pF)
	    {
		if ( pF->getValue().getType() == BLOB_TYPE && pF->getValue().getValue() != 0 )
		{
		    PageIdType pageId;
		    memcpy(&pageId, pF->getValue().getValue(), sizeof(PageIdType));
		    
		    _pGTM->decreaseBlobRef(tabSetId, pageId);
		}
		
		if ( pF->getValue().getType() == CLOB_TYPE && pF->getValue().getValue() != 0 )
		{
		    PageIdType pageId;
		    memcpy(&pageId, pF->getValue().getValue(), sizeof(PageIdType));
		    _pGTM->decreaseClobRef(tabSetId, pageId);
		}
		
		pF = execSchema.Next();
	    }

	    throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Cannot execute insert"), e);	   
	}
	
	return Chain(_affCount) + Chain(" tuples inserted");
    }
    case INSERTBYSELECT_QUERY:
    {
	CegoTableObject oe;
	ListT<CegoField> execSchema = _schema;
	
	try
	{
	    if ( _pGTM->getAutoCommit() == false )
	    {
		if ( _pGTM->getTid(_tableSet) == 0 )
		{
		    _pGTM->startTransaction(_tableSet);
		}
	    }
	    
	    unsigned tabSetId = _pGTM->getDBMng()->getTabSetId(_tableSet);
	    if ( _pGTM->objectExists(tabSetId, _tableName, CegoObject::ALIAS ))
	    {
		CegoAliasObject ae;
		_pGTM->getObject(tabSetId, _tableName, CegoObject::ALIAS, ae);

		CegoQueryHelper::mapAliasSchema(execSchema, ae.getAliasList());
		
		// get table object for alias
		_pGTM->getObject(tabSetId, ae.getTabName(), CegoObject::TABLE, oe);
	    }
	    else
	    {
		_pGTM->getObject(tabSetId, _tableName, CegoObject::TABLE, oe);
	    }
	}
	catch ( Exception e )
	{
	    throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Cannot get table"), e);    
	}
		
	if (  execSchema.isEmpty() )
	{   
	    execSchema = oe.getSchema();
	}
	else
	{	
	    /* complete missing attributes in schema */
	    ListT<CegoField> checkSchema = oe.getSchema();
	    
	    CegoField *pF = checkSchema.First();
	    while ( pF )
	    {
		CegoField *pCF = execSchema.Find(*pF);
		if ( pCF == 0  )
		{
		    if ( pF->getValue().getValue() )
		    {
			execSchema.Insert( *pF );			    
		    }
		    else if ( pF->isNullable() )
		    {
			execSchema.Insert( *pF );				
		    }
		    else
		    {
			throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Attribute ") + pF->getAttrName() + " not nullable");
		    }
		}
		else
		{
		    pCF->setType(pF->getType());
		    pCF->setLength(pF->getLength());
		    pCF->setDim(pF->getDim());		   
		}
		pF = checkSchema.Next();	    
	    }
	    
	    pF = execSchema.First();
	    while ( pF )
	    {
		CegoField *pUF = oe.getSchema().Find(*pF);
		if ( pUF )
		{
		    pF->setValue(pUF->getValue());
		    pF->setNullable(pUF->isNullable());
		}
		else
		{
		    throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Unknown attribute ") + pF->getAttrName() );
		}
		
		pF = execSchema.Next();
	    }
	}
	
	unsigned tabSetId = _pGTM->getDBMng()->getTabSetId(_tableSet);    
	ListT<CegoField> fl;
	bool moreTuple = false;
	
	try
	{
	    _pSelect->setProcBlock(pBlock);
	    _pSelect->setTabSetId(tabSetId);
	    _pSelect->prepare();	    
	    moreTuple = _pSelect->nextTuple(fl);		
	}
	catch ( Exception e )
	{
	    _pSelect->cleanUp();
	    throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Cannot get tuple"), e);
	}

	ListT< ListT<CegoField> > fva;
	
	while ( moreTuple || fva.Size() > 0 )
	{	    
	    try
	    {
		if ( moreTuple )
		{
		    ListT<CegoField> insertSchema = execSchema;
		    CegoField* pFV = insertSchema.First();
		    CegoField* pSF = fl.First();
		    
		    while ( pFV && pSF)
		    {		    
			CegoFieldValue fv = pSF->getValue();
			
			try
			{
			    CegoQueryHelper::prepareFieldValue(pFV, fv, _pGTM, oe.getTabSetId());
			}
			catch ( Exception e )
			{
			    Chain msg;
			    e.pop(msg);
			    throw CegoQueryException(COREOP_EXCEP, EXLOC, msg);
			}
			
			// we have to create a local copy, since the tuple are buffered in fva
			// and the corresponding data pages could be replaced in bufferpool ...
			pFV->setValue(fv.getLocalCopy()); 
			pFV = insertSchema.Next();
			pSF = fl.Next();	    
		    }
		    	           
		    fva.Insert(insertSchema);
		}
		
		if ( fva.Size() == MAX_CLUSTERED_INSERT || moreTuple == false)
		{
		    try
		    {
			_pGTM->insertQueryTable(oe, fva);
			_affCount += fva.Size();
			fva.Empty();
		    }
		    catch ( Exception e )
		    {
			throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Cannot insert tuple data"), e);
		    }
		}
	    }
	    catch ( CegoQueryException e )
	    {		    
		// clean clobs and blobs
		
		unsigned tabSetId = _pGTM->getDBMng()->getTabSetId(_tableSet);
		
		ListT<CegoField> *pFLA = fva.First();
		while ( pFLA )
		{
		    CegoField *pF = pFLA->First();
		    
		    while ( pF)
		    {
			if ( pF->getValue().getType() == BLOB_TYPE && pF->getValue().getValue() != 0 )
			{
			    PageIdType pageId;
			    memcpy(&pageId, pF->getValue().getValue(), sizeof(PageIdType));			    
			    _pGTM->decreaseBlobRef(tabSetId, pageId);
			}
			
			if ( pF->getValue().getType() == CLOB_TYPE && pF->getValue().getValue() != 0 )
			{
			    PageIdType pageId;
			    memcpy(&pageId, pF->getValue().getValue(), sizeof(PageIdType));
			    _pGTM->decreaseClobRef(tabSetId, pageId);
			}
			
			pF = pFLA->Next();
		    }
		    pFLA=fva.Next();
		}

		throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Cannot execute insert by select"), e);
	    }
	    
	    if ( moreTuple )
	    {
		try
		{
		    moreTuple = _pSelect->nextTuple(fl);		
		}
		catch ( Exception e )
		{
		    _pSelect->cleanUp();
		    throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Cannot get next tuple"), e);
		}
	    }	    
	}    
	
	_pSelect->cleanUp();
	
	_pGTM->getDBMng()->cleanCache( oe.getTabSetId(), CegoObject::TABLE, oe.getTabName());	    
	
	return Chain(_affCount) + Chain(" tuples inserted");
    }
    case DELETE_QUERY:
    {	
	try 
	{
	    if ( _pGTM->getAutoCommit() == false )
	    {
		if ( _pGTM->getTid(_tableSet) == 0 )
		{
		    _pGTM->startTransaction(_tableSet);
		}
	    }

	    CegoTableObject oe;
	    unsigned tabSetId = _pGTM->getDBMng()->getTabSetId(_tableSet);
	    
	    if ( _pGTM->objectExists(tabSetId, _tableName, CegoObject::ALIAS ))
	    {
		CegoAliasObject ae;
		_pGTM->getObject(tabSetId, _tableName, CegoObject::ALIAS, ae);

		CegoQueryHelper::mapAliasPredicate(_pPred, _tableAlias, ae.getAliasList());
		
		// get table object for alias
		_pGTM->getObject(tabSetId, ae.getTabName(), CegoObject::TABLE, oe);
	    }
	    else
	    {
		_pGTM->getObject(tabSetId, _tableName, CegoObject::TABLE, oe);
	    }
	    
	    oe.setTabAlias(_tableAlias);
	    _affCount = _pGTM->deleteQueryTable(oe, _pPred, pBlock);
	    _pGTM->getDBMng()->cleanCache(oe.getTabSetId(), CegoObject::TABLE, oe.getTabName() );
	}
	catch ( Exception e )
	{
	    throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Cannot delete tuple"), e);
	}

	return Chain(_affCount) + Chain(" tuples deleted");
    }
    case UPDATE_QUERY:
    {      

	ListT<CegoField> execSchema = _schema;
	CegoTableObject oe;
	
	try 
	{
	    if ( _pGTM->getAutoCommit() == false )
	    {
		if ( _pGTM->getTid(_tableSet) == 0 )
		{
		    _pGTM->startTransaction(_tableSet);
		}
	    }
	    
	    unsigned tabSetId = _pGTM->getDBMng()->getTabSetId(_tableSet);
	    if ( _pGTM->objectExists(tabSetId, _tableName, CegoObject::ALIAS ))
	    {
		CegoAliasObject ae;
		_pGTM->getObject(tabSetId, _tableName, CegoObject::ALIAS, ae);

		CegoQueryHelper::mapAliasPredicate(_pPred, _tableAlias, ae.getAliasList());
		CegoQueryHelper::mapAliasSchema(execSchema, ae.getAliasList());
		
		// get table object for alias
		_pGTM->getObject(tabSetId, ae.getTabName(), CegoObject::TABLE, oe);
	    }
	    else
	    {
		_pGTM->getObject(tabSetId, _tableName, CegoObject::TABLE, oe);
	    }
	}
	catch ( Exception e )
	{
	    throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Cannot update tuple"), e);    
	}

	oe.setTabAlias(_tableAlias);
	
	CegoField *pF = execSchema.First();
	while ( pF )
	{	    
	    if ( _tableName != _tableAlias )
	    {	    
		pF->setTableAlias(_tableAlias);
	    }

	    CegoField *pUF = oe.getSchema().Find(*pF);
	    if ( pUF )
	    {		
		pF->setLength(pUF->getLength());
		pF->setDim(pUF->getDim());		
		pF->setType(pUF->getType());
		pF->setNullable(pUF->isNullable());		
		pF->setValue(pUF->getValue());
	    }
	    else
	    {
		throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Unknown attribute ") + pF->getAttrName() );
	    }
	    
	    pF = execSchema.Next();
	}

	ListT<CegoField> returnList;
	
	try 
	{
	    _affCount = _pGTM->updateQueryTable(oe, _pPred, execSchema, _updList, _returnOnFirst, returnList,  pBlock);
	    _pGTM->getDBMng()->cleanCache( oe.getTabSetId(), CegoObject::TABLE, oe.getTabName());
	}
	catch ( Exception e )
	{
	    throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Cannot update tuple"), e);
	}
		
	CegoReturnVar **pRV = _retVarList.First();
	while ( pRV ) 
	{	    
	    if ( pBlock )
	    {	
		CegoExpr *pExpr = (*pRV)->getExpr();

		// we need to create an additional reference to use the setFieldListArray method
		ListT<CegoField>* fl[2];
		// fl[0] = &_schema;
		fl[0] = &returnList;
		fl[1] = 0;
				
		// pExpr->setFieldListArray(fl);
		CegoFieldValue fv = pExpr->evalFieldValue(fl, pBlock);
		
		pBlock->setValue((*pRV)->getVarName(), fv); 
	    }
	    pRV = _retVarList.Next();
	}

	return Chain(_affCount) + Chain(" tuples updated");
    }
    case ALTER_QUERY:
    {
	// alter query is not transaction safe
 
	CegoTableObject oe;

	unsigned tabSetId = _pGTM->getDBMng()->getTabSetId(_tableSet);
		    
	try
	{
	    _pGTM->getObject(tabSetId, _tableName, CegoObject::TABLE, oe);
	    _pGTM->alterQueryTable(oe, _alterList);
	    _affCount++;
	    _pGTM->getDBMng()->cleanCache(oe.getTabSetId(), CegoObject::TABLE, oe.getTabName());
	}
	catch ( Exception e )
	{
	    throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Cannot alter table"), e);    
	}
	    
	return Chain("Table altered");
    }
    case RENAME_QUERY:
    {
	// rename query is not transaction safe

	unsigned tabSetId = _pGTM->getDBMng()->getTabSetId(_tableSet);
	
	if ( _objType == CegoObject::TABLE )
	{
	    CegoTableObject oe;
	    
	    try
	    {		
		_pGTM->getObject(tabSetId, _objName, _objType, oe);	
	    }
	    catch ( Exception e )
	    {
		Chain msg;
		while ( e.pop(msg) );
		throw CegoQueryException(COREOP_EXCEP, EXLOC, msg);    
	    }
	    _pGTM->getDBMng()->cleanCache(oe.getTabSetId(), CegoObject::TABLE, oe.getTabName() );	    
	}
	
	try 
	{
	    _pGTM->renameQueryObject(_tableSet, _objName, _objType, _newObjName);
	    _affCount++;
	}
	catch ( Exception e )
	{
	    throw CegoQueryException(COREOP_EXCEP, EXLOC, Chain("Cannot rename table"), e);   
	}
	return Chain("Object renamed");	
    }
    default:
        throw Exception(EXLOC, Chain("Unknown query mode"));
    }
}

void CegoQuery::cleanUp()
{
    
    CegoExpr **pExpr = _updList.First();
    while ( pExpr )
    {
	(*pExpr)->cleanUp();
	pExpr = _updList.Next();
    }

    ListT<CegoExpr*> *pExprList = _exprListArray.First();
    while ( pExprList )
    {
	CegoExpr **pExpr = pExprList->First();
	while ( pExpr )
	{
	    (*pExpr)->cleanUp();
	    pExpr = pExprList->Next();
	}
	pExprList = _exprListArray.Next();
    }

    if ( _pPred )
	_pPred->cleanUp();
    if ( _pSelect )
	_pSelect->cleanUp();
}

long CegoQuery::getAffectedCount() const
{
    return _affCount;
}

Chain CegoQuery::toChain(unsigned defTabSetId, const Chain& indent) const
{
    Chain s;
    switch ( _mode )
    {
    case START_QUERY:
    {
	s = Chain("start transaction");
	break;
    }
    case COMMIT_QUERY:
    {
	s = Chain("commit");
	break;
    }
    case ROLLBACK_QUERY:
    {
	s = Chain("rollback");
	break;
    }
    case LOCK_QUERY:
    {
	s = Chain("lock table ") + _tableName;
	break;
    }
    case UNLOCK_QUERY:
    {
	s = Chain("unlock table ") + _tableName;
	break;
    }
    case INSERT_QUERY:
    {	
	s = Chain("insert into ") + _tableName;

	if ( _schema.Size() > 0 )
	{
	    CegoField* pFV = _schema.First();
	    
	    s += " ( ";	
	    
	    while ( pFV )
	    {
		s += pFV->getAttrName();
		pFV = _schema.Next();
		if ( pFV  )
		    s += Chain(", ");
	    }
	    
	    s += Chain(" )"); 
	}
	s += Chain("\n") + indent + Chain("values ");

	ListT<CegoExpr*> *pExprList = _exprListArray.First();
	while ( pExprList )
	{
	    s += Chain("("); 
	
	    CegoExpr **pExpr = pExprList->First();
	    while ( pExpr )
	    {
		s += (*pExpr)->toChain(defTabSetId);
		pExpr = pExprList->Next();
		if ( pExpr )
		    s += Chain(", ");
	    }
	    s += Chain(")");
	    pExprList = _exprListArray.Next();
	    if ( pExprList )
		s += Chain(", ");		
	}
	break;
    }
    case INSERTBYSELECT_QUERY:
    {
	s = Chain("insert into ") + _tableName;

	if ( _schema.Size() > 0 )
	{
	    CegoField* pFV = _schema.First();
	    
	    s += Chain(" ( ");	
	    
	    while ( pFV )
	    {
		s += pFV->getAttrName();
		pFV = _schema.Next();
		if ( pFV  )
		    s += Chain(", ");
	    }
	    
	    s += Chain(" )"); 
	}
	s += Chain("\n") + indent + indent;
	s += _pSelect->toChain(defTabSetId, indent + indent);

	break;
    }
    case DELETE_QUERY:
    {
	s = Chain("delete from ") + _tableName;

	if ( _tableName != _tableAlias )
	    s += Chain(" ") + _tableAlias;

	if (_pPred)
	{
	    s += Chain("\n") + indent + indent + Chain("where ");		   
	    s += _pPred->toChain(defTabSetId, indent + indent);
	}
	break;
    }
    case UPDATE_QUERY:
    {
	s = Chain("update ") + _tableName;

	if ( _tableName != _tableAlias )
	    s += Chain(" ") + _tableAlias;
	
	s += Chain(" set ");

	CegoField* pFV = _schema.First();
	CegoExpr** pExpr = _updList.First();
		    
	while ( pFV && pExpr)
	{	    
	    s += pFV->getAttrName() + Chain("=") + (*pExpr)->toChain(defTabSetId);
	    pFV = _schema.Next();
	    pExpr = _updList.Next();
	    if ( pFV && pExpr )
		s += Chain(",\n") + indent;
	}
	
	if (_pPred)
	{
	    s += Chain("\n") + indent + indent + Chain("where ");
	    s += _pPred->toChain(defTabSetId, indent + indent);
	}

	if ( _retVarList.isEmpty() == false )
	{ 
	    if ( _returnOnFirst )
		s += Chain(" return on first ");
	    else
		s += Chain(" return ");
		
	    CegoReturnVar **pRV = _retVarList.First();
	    while ( pRV ) 
	    {
		s += (*pRV)->toChain(defTabSetId);
		pRV = _retVarList.Next();
		if ( pRV ) 
		    s += Chain(",\n") + indent; 
	    }
	}
	break;
    }
    case ALTER_QUERY:
    {
	s = Chain("alter ") + _tableName + Chain(" ");
	CegoAlterDesc *pAD = _alterList.First();
	while ( pAD ) 
	{
	    s += pAD->toChain();
	    pAD = _alterList.Next();
	    if ( pAD ) 
		s += ",";
	}
	break;
    }
    case RENAME_QUERY:
    {
	s = Chain("rename ");
	switch ( _objType )
	{
	case CegoObject::TABLE:
	{
	    s += Chain("table ");
	    break;
	}
	case CegoObject::AVLTREE:
	case CegoObject::PAVLTREE:
	case CegoObject::UAVLTREE:
	{
	    s += Chain("avl ");
	    break;
	}
	case CegoObject::BTREE:
	case CegoObject::PBTREE:
	case CegoObject::UBTREE:
	{
	    s += Chain("btree ");
	    break;	    
	}
	case CegoObject::FKEY:
	{
	    s += Chain("key ");
	    break;
	}
	case CegoObject::PROCEDURE:
	{
	    s += Chain("procedure ");
	    break;
	}
	case CegoObject::VIEW:
	{
	    s += Chain("view ");
	    break;
	}
	case CegoObject::CHECK:
	{
	    s += Chain("check ");
	    break;	    
	}
	case CegoObject::SYSTEM:
	case CegoObject::TRIGGER:
	case CegoObject::ALIAS:
	case CegoObject::RBSEG:
	case CegoObject::JOIN:
	case CegoObject::UNDEFINED:	    	    	   	 	    
	    throw Exception(EXLOC, "Invalid object");
	}
	s += _objName + Chain(" to ") + _newObjName;

	break;
    }
    }
    return s;    
}

Chain CegoQuery::dbFormat(CegoDatabaseFormater *pForm) const
{
    return pForm->formatQuery(_mode, _tableName, _tableAlias, _schema,  _exprListArray,  _updList, _retVarList, _alterList, _pPred, _pSelect, _objName, _objType, _newObjName);
}
