#ifndef _CEGOTABLEMANAGER_H_INCLUDED_
#define _CEGOTABLEMANAGER_H_INCLUDED_
///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoTableManager.h
// ------------------
// Cego table manager class definition
// 
// Design and Implementation by Bjoern Lemke
//
// (C)opyright 2000-2019 Bjoern Lemke
//
// INTERFACE MODULE
//
// Class: CegoTableManager
// 
// Description: Basic table management
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

// base includes
#include <lfcbase/Chain.h>
#include <lfcbase/ListT.h>

// xml includes
#include <lfcxml/XMLOutStream.h>

// cego includes
#include "CegoDataType.h"
#include "CegoTupleState.h"
#include "CegoField.h"
#include "CegoPredDesc.h"
#include "CegoQueryHelper.h"
#include "CegoLockHandler.h"
#include "CegoTransactionManager.h"
#include "CegoAlterDesc.h"
#include "CegoDefs.h"
#include "CegoProcedure.h"
#include "CegoView.h"
#include "CegoSystemObject.h"
#include "CegoBTreeValue.h"
#include "CegoTrigger.h"

class CegoTransactionManager;
class CegoDbThreadPool;

class CegoTableManager : public CegoSystemObject {

public:

    enum IsolationLevel { READ_COMMITTED, READ_UNCOMMITTED };

    CegoTableManager(CegoDatabaseManager *pDBMng);
    ~CegoTableManager();

    void setThreadId(unsigned long long tid);
    unsigned long long getThreadId() const;
    
    void setAppend(bool doAppend);

    void createBasicTableSet(const Chain& tableSet);
    void dropTableSet(const Chain& tableSet);
    void reorgTableSet(const Chain& tableSet);

    void stopTableSet(const Chain& tableSet, bool archComplete);

    void resetTableSet(const Chain& tableSet);

    void beginBackup(const Chain& tableSet, const Chain& msg);
    void endBackup(const Chain& tableSet, const Chain&msg, bool keepTicket = true);
    void resetBUStat(const Chain& tableSet);

    void syncTableSet(const Chain& tableSet, const Chain& msg, const Chain& escCommand, int timeout);

    void logTo(const Chain& tableSet, const Chain& secondary);

    void addDataFile(const Chain& tableSet, const Chain& type, int fileId, const Chain& dataFile, int fileSize);
    
    // transaction methods

    void setIsolationLevel(IsolationLevel level);
    IsolationLevel getIsolationLevel() const;
    
    void setAutoCommit(bool autoCommit);
    bool getAutoCommit() const;

    void lockTable(int tabSetId, const Chain& tableName);
    void unlockTable(int tabSetId, const Chain& tableName);
    
    void beginTransaction(int tabSetId, bool doLog);
    void getTransactionAffectedTables(int tabSetId, SetT<Chain>& tableList);

    unsigned long long commitTransactionSynced(int tabSetId);
    unsigned long long commitTransaction(int tabSetId, bool doLog);

    unsigned long long rollbackTransactionSynced(int tabSetId);
    unsigned long long rollbackTransaction(int tabSetId, bool doLog);
    
    unsigned long long getTID(int tabSetId);

    void setTAStep(int tabSetId, unsigned long long tastep);
    unsigned long long getTAStep(int tabSetId);

    void setTID(int tabSetId, unsigned long long tid);

    void getTupleInfo(int tabSetId, const CegoDataPointer dp, unsigned long long &tid, unsigned long long &tastep, CegoTupleState &ts);
    void setTupleInfo(int tabSetId, const CegoDataPointer dp, unsigned long long tid, unsigned long long tastep, CegoTupleState ts);

    // table methods

    CegoTableObject createDataTable(int tabSetId, const Chain& tableName, CegoObject::ObjectType type, const ListT<CegoField>& fl, bool useColumnId = false);

    void alterDataTableSynced(CegoTableObject& oe, const ListT<CegoAlterDesc>& alterList);
    void alterDataTable(int tabSetId, const Chain& tableName, CegoObject::ObjectType type, const ListT<CegoAlterDesc>& alterList);
    
    void renameObject(int tabSetId, const Chain& objName,  CegoObject::ObjectType type, const Chain& newObjName);

    void reorgObjectSynced(int tabSetId, const Chain& objName, CegoObject::ObjectType type);
    void reorgTable(int tabSetId, const Chain& tableName);

    void invalidateIndexForTable(int tabSetId, const Chain& tableName);
    
    void insertDataTable(CegoTableObject& oe,
			 ListT<CegoField>& fvl,
			 CegoDataPointer& dp, 
			 bool doLogging, bool flushLog);
    

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

    unsigned long long deleteDataTable(CegoTableObject& oe, CegoPredDesc* pPred, CegoProcBlock* pBlock, bool isSynced);
    unsigned long long deleteDataTable(CegoTableObject& oe,
				       const ListT<CegoTableObject>& idxList,
				       const ListT<CegoBTreeObject>& btreeList,
				       const ListT<CegoKeyObject>& keyList,
				       CegoPredDesc* pPred, CegoProcBlock* pBlock, bool isSynced);

    void deleteDataTableEntrySynced(int tabSetId, 
				    const Chain& tableName,
				    CegoObject::ObjectType type, 
				    const CegoDataPointer& dp,
				    const ListT<CegoField>& fvl, 
				    const ListT<CegoTableObject>& idxList,
				    const ListT<CegoBTreeObject>& btreeList,
				    const ListT<CegoKeyObject>& keyList,
				    bool doCheckKey, 
				    bool doIgnoreIndexError,
				    bool isSynced);
    
    bool deleteDataTableEntry(int tabSetId, 
			      const Chain& tableName,
			      CegoObject::ObjectType type, 
			      const CegoDataPointer& dp,
			      const ListT<CegoField>& fvl,
			      const ListT<CegoTableObject>& idxList,
			      const ListT<CegoBTreeObject>& btreeList,
			      const ListT<CegoKeyObject>& keyList,
			      bool doCheckKey = true, 
			      bool doIgnoreIndexError = false);

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

    void truncateTable(int tabSetId, const Chain& tableName);
    void dropObjectSynced(int tabSetId, const Chain& objName, CegoObject::ObjectType type);
	
    void dropTable(int tabSetId, 
		   const Chain& tableName);
	
    void dropIndex(int tabSetId, const Chain& idxName);
    void dropBTree(int tabSetId, const Chain& btreeName);

    void dropView(int tabSetId, const Chain& viewName);
    void dropProcedure(int tabSetId, const Chain& procName);
    void dropFKey(int tabSetId, const Chain& fkey);
    void dropCheck(int tabSetId, const Chain& check);
    void dropTrigger(int tabSetId, const Chain& trigger);
    void dropAlias(int tabSetId, const Chain& aliasName);
    void correctTableSet(int tabSetId, bool doSync);

    void correctIndexForTable(int tabSetId, const Chain& tableName, bool doSync, bool doForce);

    int cleanTableSet(int tabSetId);
    
    // utility cursor for native table traverse

    bool getFirstTuple(CegoObjectCursor* pC, ListT<CegoField>& fl, CegoDataPointer& dp);
    bool getNextTuple(CegoObjectCursor* pC, ListT<CegoField>& fl, CegoDataPointer& dp);


    // index and key creation

    void createIndexTableSynced(int tabSetId, const Chain& indexName, const Chain& tableName, CegoObject::ObjectType type, ListT<CegoField>& idxList, bool isCached);
	
    void createPrimaryIndexTable(int tabSetId, const Chain& indexName, const Chain& tableName, ListT<CegoField>& schema);

    void createIndexTable(int tabSetId, const Chain& indexName, const Chain& tabName, ListT<CegoField>& schema, CegoObject::ObjectType type, bool isCached);

    void createBTree(int tabSetId, const Chain& btreeName, const Chain& tableName, ListT<CegoField>& schema, CegoObject::ObjectType type, bool doSync, bool isCached);

    void createAVLIndexTable(int tabSetId, const Chain& indexName, const Chain& tableName, ListT<CegoField>& schema, CegoObject::ObjectType type);

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

    void createCheck(int tabSetId, const Chain& checkName, const Chain& tableName, CegoPredDesc *pPredDesc);
    
    void createTrigger(int tabSetId, const Chain& triggerName,
		       bool isBefore, bool isOnInsert, bool isOnUpdate, bool isOnDelete,
		       const Chain& tableName, const Chain& triggerText);
		       
    void createAlias(int tabSetId, const Chain& aliasName, const Chain& tableName, const ListT<CegoAttrAlias>& aliasList);

    
    // info methods

    void getPoolInfo(CegoTableObject& oe, ListT< ListT<CegoFieldValue> > &info);
    void getSystemInfo(const Chain& tableSet, CegoTableObject& oe,  ListT< ListT<CegoFieldValue> > &fa, Chain& format);

    // debugging methods

    void dumpObject(const Chain& tableSet, const Chain& tableName, CegoObject::ObjectType type, Chain& chainDump);
    void dumpObject(int tabSetId, const Chain& tableName, CegoObject::ObjectType type, Chain& chainDump);
    // void dumpLockHandler(Chain& lockDump);

    void regDataFiles(const Chain& tableSet);
    
    void abort();
    void proceed();
    bool isAborted() const;
    
    void addCompProcedure(int tabSetId, CegoProcedure *pProc);
    void removeCompProcedure(int tabSetId, const Chain& procName);
    bool checkCompProcedure(int tabSetId, const Chain& procName);
    CegoProcedure* getCompProcedure(int tabSetId, const Chain& procName);

    void addCompView(int tabSetId, CegoView *pView);
    void removeCompView(int tabSetId, const Chain& viewName);
    bool checkCompView(int tabSetId, const Chain& viewName);
    CegoView* getCompView(int tabSetId, const Chain& viewName);

    void addCompTrigger(int tabSetId, CegoTrigger *pTrigger);
    void removeCompTrigger(int tabSetId, const Chain& triggerName);
    bool checkCompTrigger(int tabSetId, const Chain& triggerName);
    CegoTrigger* getCompTrigger(int tabSetId, const Chain& triggerName);

    void removeAllComp(int tabSetId);    

    void getTSLockStat(int tabSetId, Chain& lockName, int& lockCount, unsigned long long &numRdLock, unsigned long long &numWrLock, unsigned long long &sumRdDelay, unsigned long long &sumWrDelay);
    void getLHLockStat(unsigned long long lockId, Chain& lockName, int& lockCount, unsigned long long &numRdLock, unsigned long long &numWrLock, unsigned long long &sumRdDelay, unsigned long long &sumWrDelay);
    void getLHAggLockStat(const Chain& lockName, int& numLock, int& lockCount, unsigned long long &numRdLock, unsigned long long &numWrLock, unsigned long long &sumRdDelay, unsigned long long &sumWrDelay);
    
    void extractIndexValue(const ListT<CegoField>& tableSchema, const ListT<CegoField>& indexSchema, char* p, int len, int& idxLen);

    void increaseBlobRef(int tabSetId, PageIdType pageId);
    void decreaseBlobRef(int tabSetId, PageIdType pageId);

    void increaseClobRef(int tabSetId, PageIdType pageId);
    void decreaseClobRef(int tabSetId, PageIdType pageId);

    unsigned char* getBlobData(int tabSetId, PageIdType pageId, unsigned long long& blobSize);
    char* getClobData(int tabSetId, PageIdType pageId, unsigned long long& clobSize);
    
    void putBlobData(int tabSetId, unsigned char* data, unsigned long long blobSize, PageIdType& pageId);
    void putClobData(int tabSetId, char* data, unsigned long long clobSize, PageIdType& pageId);
    
    CegoTransactionManager* getTransactionManager();

    void setPoolSyncInfo(CegoDbThreadPool *pPool, int thrIdx);

protected:

    CegoTransactionManager *_pTM;
	
    void resetTemp(const Chain& tableSet);
    
    void finishOpenTransaction(int tabSetId);
    unsigned long long _threadId;

    bool _doAppend;
    
    
private:
    
    void renameTable(int tabSetId, const Chain& tableName, const Chain& newTableName);
    void renameIndex(int tabSetId, const Chain& idxName, CegoObject::ObjectType type, const Chain& newIdxName);

    void renameBTree(int tabSetId, const Chain& btreeName, CegoObject::ObjectType type, const Chain& newBTreeName);

    void renameKey(int tabSetId, const Chain& keyName, const Chain& newKeyName);
    void renameProcedure(int tabSetId, const Chain& keyName, const Chain& newKeyName);
    void renameView(int tabSetId, const Chain& viewName, const Chain& newViewName);
    void renameCheck(int tabSetId, const Chain& checkName, const Chain& newCheckName);
    void renameTrigger(int tabSetId, const Chain& triggerName, const Chain& newTriggerName);
    void renameRBO(int tabSetId, const Chain& rboName, const Chain& newRboName);

    bool updateTuple(CegoTableObject& oe,  const CegoDataPointer& sysEntry, const CegoDataPointer& dp, 
		     ListT<CegoField>& fl,
		     const ListT<CegoField>& nfvl,
		     ListT<CegoExpr*>& exprList,
		     ListT<CegoField>& updSchema, 
		     const ListT<CegoTableObject>& idxList,
		     const ListT<CegoBTreeObject>& btreeList,
		     const ListT<CegoKeyObject>& keyList,
		     const ListT<CegoCheckObject>& checkList,
		     const Chain& virginIndex,
		     bool doAppend, 
		     CegoProcBlock* pBlock);

    
    void checkTypes(const ListT<CegoField>& fl, const ListT<CegoField>& nfl);    
    void checkIntegrity(int tabSetId, const Chain& tableName,
			const ListT<CegoTableObject>& idxList,
			const ListT<CegoBTreeObject>& btreeList,
			const ListT<CegoKeyObject>& keyList,
			const ListT<CegoCheckObject>& checkList,
			const CegoDataPointer& dp, const ListT<CegoField>& fvl, const ListT<CegoField>& nfvl);

    void getKeyAndIdxRef(int tabSetId, const Chain& tableName, const Chain& attrName, ListT<CegoKeyObject>& refKeyList, ListT<CegoTableObject>& refIdxList, ListT<CegoBTreeObject>& refBTreeList);
    void checkKeyIntegrity(const ListT<CegoKeyObject>& keyList, int tabSetId, const Chain& tableName, const ListT<CegoField>& fvl, const ListT<CegoField>& nfvl);
    void checkIndexIntegrity(const ListT<CegoTableObject>& idxList, int tabSetId, const CegoDataPointer& dp, const ListT<CegoField>& fvl, const ListT<CegoField>& nfvl);
    void checkBTreeIntegrity(const ListT<CegoBTreeObject>& btreeList, int tabSetId, const CegoDataPointer& dp, const ListT<CegoField>& fvl, const ListT<CegoField>& nfvl);
    void checkCheckIntegrity(const ListT<CegoCheckObject>& checkList, const ListT<CegoField>& nfvl);
    bool checkNullValue(int tabSetId, const Chain& tableName, const CegoField& f);

    bool keyReferenceExists(int tabSetId, const Chain& tableName, const ListT<CegoField>& fl, const ListT<CegoKeyObject>& keyList);
	
    const CegoFieldValue& getIndexSearchValue(const ListT<CegoField>& idxSchema, const ListT<CegoField>& nfvl);

    void getBlobs(int tabSetId, const ListT<CegoField>& fvl, ListT<CegoBlob>& blobList);
    void getClobs(int tabSetId, const ListT<CegoField>& fvl, ListT<CegoClob>& clobList);

    void getBlobs(int tabSetId, ListT<CegoExpr*>& exprList, CegoProcBlock* pBlock, ListT<CegoBlob>& blobList);
    void getClobs(int tabSetId, ListT<CegoExpr*>& exprList, CegoProcBlock* pBlock, ListT<CegoClob>& clobList);

    void addBUStat(int tabSetId, const Chain& butype, const Chain& msg);

    bool typeConversionAllowed(CegoDataType fromType, CegoDataType toType);

    void getClobForExprList(int tabSetId, ListT<CegoExpr*>& exprList, ListT<CegoClob>& clobList);
	
    void poolP();
    void poolV();

    unsigned long long _tid[TABMNG_MAXTABSET];

    // tastep is an opertion counter inside a single transaction
    // it is used for object cursors to filter out the current transaction operation
    // but rather acces previous modified tuples ( condition : taset(tuple) < tastep(current) )

    unsigned long long _tastep[TABMNG_MAXTABSET];

    ListT<CegoField> _streamSchema;

    bool _isAborted;
    bool _autoCommit;

    int _encBufLen;
    char *_pEncBuf;

    IsolationLevel _isolationLevel;

    ListT<CegoProcedure*> _procList[TABMNG_MAXTABSET];
    ListT<CegoView*> _viewList[TABMNG_MAXTABSET];
    ListT<CegoTrigger*> _triggerList[TABMNG_MAXTABSET];

    CegoDbThreadPool *_pPool;
    int _thrIdx;
    
    unsigned long _modId;
};

#endif
