/*!***************************************************************************

  module      : SQLMan_PascalWrapper.cpp

  -------------------------------------------------------------------------

  responsible : ThomasA

  special area: SQL Manager
  description : defines PASCAL interface of SQL manager.

  last changed: 2000-12-06  19:04
  see also    : example.html ...
  first created:2000-03-09  18:21

  -------------------------------------------------------------------------

  copyright:    (c) 2000-2004 SAP AG




    ========== licence begin  GPL
    Copyright (c) 2000-2005 SAP AG

    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
    of the License, 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; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end




*****************************************************************************/

#include "hak01.h"
#include "hak06.h"
#include "hak07.h"
#include "hak071.h"
#include "hak10.h"
#include "hak101.h"
#include "hsp77.h"
// next two to be excluded if 'new' messagelist can be used without old one
#include "geo200.h"
#include "SAPDBCommon/ErrorsAndMessages/SAPDBErr_MessageEventConverter.hpp"

#include "SAPDBCommon/MemoryManagement/SAPDBMem_NewDestroy.hpp"
#include "SAPDBCommon/Tracing/SAPDBTrace_Hex.hpp"
#include "SQLManager/SQLMan_Context.hpp"
#include "SQLManager/SQLMan_SessionInfo.hpp"
#include "SQLManager/SQLMan_SessionList.hpp"
#include "SQLManager/SQLMan_Tracing.hpp"
#include "SQLManager/SQLMan_Messages.hpp"
#include "SQLManager/SQLMan_MessBlock.hpp"
#include "SQLManager/SharedSQL/SharedSQL_SQLCache.hpp"
#include "SQLManager/Catalog/Catalog_SessionCache.hpp"
#include "SQLManager/Catalog/Catalog_TableObject.hpp"
#include "SQLManager/Catalog/Catalog_SharedSqlObject.hpp"
#include "SQLManager/Catalog/Catalog_Interface.hpp"
//#include "SQLManager/Catalog/Catalog_Instance.hpp"
#include "SQLManager/DBProc/DBProc_Debugger.hpp"
#include "SQLManager/ErrorHandling/SQLManErr_Instance.hpp"
#include "RunTime/RTE_Message.hpp"
#include "KernelCommon/Kernel_OpMsg.hpp"
#include "RunTime/RTE_MySQLProxy.h"
#include "Join/Join_HashAccessAllocator.hpp"
#include "IOManager/IOMan_IDataInfo.hpp"

// for test purposes the shared sql allocator can be write protected
// except in the shared sql interface routines. This allows to find
// source code that unauthorized writes into data stored in the
// shared sql component. 
// caution : this works in a single user environment only !

// DirkT: To switch on SharedSQL Protection use praeprozesor define in SharedSQL_Types.hpp instead of the following !!!
//#define SHAREDSQL_PROTECT 1  

#define SQLMAN_SHARED_SQL_TRACE(X) \
if (SharedSQL_Trace.TracesLevel (3)) {\
    SAPDBTrace_Stream stream (&SharedSQL_Trace.GetTracePrinter ());\
    stream << X << NewLine;\
}

inline SAPDB_OStream & operator<< (SAPDB_OStream & ostream, const SharedSQL_ParseID & parseId)
{
    SAPDBTrace_Hex hex(&parseId, sizeof(parseId));
    return hex.Print(ostream);
}

#if defined (SHAREDSQL_PROTECT)
class SQLMan_AllocatorWriteUnProtector
{
public :
    SQLMan_AllocatorWriteUnProtector(SAPDBMem_RawAllocator* pAllocator)
        : m_pAllocator(pAllocator)
    {
        if (m_pAllocator)
        {
            m_pAllocator->Unprotect();
        }
    };
    ~SQLMan_AllocatorWriteUnProtector()
    {
        if (m_pAllocator)
        {
            m_pAllocator->WriteProtect();
        }
    }
private :
   SAPDBMem_RawAllocator* m_pAllocator;
};

static SAPDBMem_RawAllocator* m_pSharedSQLAllocator = 0;

#define SQLMAN_UNPROTECT_ALLOCATOR(A) if (0 == m_pSharedSQLAllocator) \
                                         m_pSharedSQLAllocator = A;   \
                                      SQLMan_AllocatorWriteUnProtector unprotector(m_pSharedSQLAllocator);
#else
#define SQLMAN_UNPROTECT_ALLOCATOR(A)
#endif

//-------------------------------------------------------------------------

void a101_AnalyzeErrorMessageList (
    tak_all_command_glob  VAR_VALUE_REF  acv)
{
	teo200_EventList                    eventList;
    teo200_EventList                    tmpEventList;
    SAPDB_UInt4                         bufferSize;
    SAPDB_UInt4                         eventDataSize;
    SAPDB_UInt4                         minEventDataSize;
    tsp1_part                          *pError;
    SAPDB_Byte                         *pMsgText;
    
	SAPDBTRACE_ROUTINE_DEBUG ("a101_AnalyzeErrorMessageList", SQLMan_Trace, 1);
    SQLMan_Context& context = SQLMan_Context::AcvToContext(acv);
    if (!context.GetErrorList().IsEmpty())
    {
		RTE_Message (context.GetErrorList());
	    SAPDBErr_ConvertMessageToEventList (context.GetErrorList(), eventList);
	    bufferSize = eventList.eo200_DataBufferSize (&minEventDataSize);
		if (NULL == context.GetCurrentReturnPartPtr())
		{
			a06init_curr_retpart (acv);
		}

		pError = context.GetCurrentReturnPartPtr();
		pMsgText = REINTERPRET_CAST(SAPDB_Byte*, pError) + sizeof (pError->sp1p_part_header());
		if (eventList.eo200_StoreEventList (pMsgText, context.GetCurrentReturnPartPtr()->sp1p_buf_size(), 
			eventDataSize, true, &tmpEventList))
		{
			pError->sp1p_buf_len() = eventDataSize;
			a06finish_curr_retpart (acv, sp1pk_message_list, 1);
		}

		context.GetErrorList().ClearMessageList();	 
	 }
}

//-------------------------------------------------------------------------

void a101_AttachColumnBuffer (
    tgg00_VoidPtr                        pTable)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_AttachColumnBuffer", SQLMan_Trace, 1);
    //SAPDBERR_ASSERT_STATE( a01SharedSqlEnabled );
    SQLMAN_UNPROTECT_ALLOCATOR(0);
    REINTERPRET_CAST(Catalog_TableObject*, pTable)->IncColBufferRefCount();
}

//-------------------------------------------------------------------------

pasbool a101_CheckMySqlPassword (
    tak_all_command_glob  VAR_VALUE_REF  acv,
    tsp00_Name            VAR_ARRAY_REF  password,
    pasbool                              isOldVersion,
    tsp00_C8              VAR_ARRAY_REF  receivedPassword)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_CheckMySqlPassword", SQLMan_Trace, 1);
    tsp00_Int4 hash0, hash1;
    RTE_GetMySQLHash(hash0, hash1, password);
    return RTE_CheckMySQLPassword(receivedPassword, isOldVersion, acv.a_challenge, hash0, hash1);
}

//-------------------------------------------------------------------------

pasbool a101_DebuggerActive (
    tgg00_TransContext    VAR_VALUE_REF  transContext)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_DebuggerActive", SQLMan_Trace, 1);
    tak_all_command_glob* pAcv = REINTERPRET_CAST(tak_all_command_glob*, transContext.trAcvPtr_gg00);
    return (pAcv && (NULL != SQLMan_Context::AcvToContext(*pAcv).GetDBProcDebugger()));
}

//-------------------------------------------------------------------------

void a101_DebuggerCheckDebugBreak (
    tgg00_TransContext       VAR_VALUE_REF  transContext,
    tgg00_SelectFieldsParam  VAR_VALUE_REF  interpreterContext,
    integer                                 currStackEntry,
    tsp00_MoveObjPtr                        pVariables,
    integer                                 codePos,
    integer                                 codeLength)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_DebuggerCheckDebugBreak", SQLMan_Trace, 1);
    tak_all_command_glob* pAcv = REINTERPRET_CAST(tak_all_command_glob*, transContext.trAcvPtr_gg00);
    DBProc_Debugger* pDebugger = SQLMan_Context::AcvToContext(*pAcv).GetDBProcDebugger();
    if (pDebugger)
    {
        tak_sysbufferaddress p  = REINTERPRET_CAST(tak_sysbufferaddress, interpreterContext.sfp_pl_ptr());
        SQLMan_MessBlock* pCode = REINTERPRET_CAST(SQLMan_MessBlock*, &p->smessblock().mbr_mess_block);
        int type                = (mm_trigger == pCode->mb_type2()) ? p->syskey().slinkage()[1] : 1; 
        pDebugger->checkDebugBreak(pCode->GetTableId(), type, currStackEntry, 
            REINTERPRET_CAST(tsp00_MoveObjPtr, interpreterContext.sfp_rec_addr()), pVariables, codePos, codeLength);  
    }
}

//-------------------------------------------------------------------------

void a101_DebuggerCreate (
    tak_all_command_glob  VAR_VALUE_REF  debuggingAcv,
    tak_all_command_glob  VAR_VALUE_REF  debuggedAcv,
    tak_all_command_glob  VAR_VALUE_REF  listenerAcv)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_DebuggerCreate", SQLMan_Trace, 1);
    DBProc_Debugger::createDebugger(SQLMan_Context::AcvToContext(debuggingAcv), 
        SQLMan_Context::AcvToContext(debuggedAcv),
        SQLMan_Context::AcvToContext(listenerAcv));
}

//-------------------------------------------------------------------------

void a101_DebuggerGetExecuteInfo (
    tsp00_MoveObjPtr                     pInfo,
    integer                              size)
{
    DBProc_Debugger::getExecuteInfo (pInfo, size);
}

//-------------------------------------------------------------------------

void a101_DebuggerGetMethodInfo (
    tak_all_command_glob  VAR_VALUE_REF  acv,
    tgg00_Surrogate       VAR_ARRAY_REF  methodId,
    integer               VAR_VALUE_REF  methodKind,
    integer               VAR_VALUE_REF  linkage,
    tsp00_MoveObjPtr      VAR_VALUE_REF  pTriggerColumns,
    tsp00_MoveObjPtr      VAR_VALUE_REF  pVariables)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_DebuggerGetMethodInfo", SQLMan_Trace, 1);
    DBProc_Debugger* pDebugger = SQLMan_Context::AcvToContext(acv).GetDBProcDebugger();
    if (pDebugger)
    {
        pDebugger->getInfo (methodId, methodKind, linkage, pTriggerColumns, pVariables);
    }
}

//-------------------------------------------------------------------------

void a101_DebuggerListen (
    tak_all_command_glob  VAR_VALUE_REF  acv,
    tgg00_Surrogate       VAR_ARRAY_REF  methodId,
    integer               VAR_ARRAY_REF  procKind,  
    integer               VAR_ARRAY_REF  linkage,  
    integer               VAR_VALUE_REF  pos,
    integer               VAR_VALUE_REF  length)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_DebuggerListen", SQLMan_Trace, 1);
    DBProc_Debugger* pDebugger = SQLMan_Context::AcvToContext(acv).GetDBProcDebugger();
    if (pDebugger)
    {
        pDebugger->listen(methodId, procKind, linkage, pos, length);
    }

}

//-------------------------------------------------------------------------

void a101_DebuggerStep (
    tak_all_command_glob  VAR_VALUE_REF  acv,
    integer                              count)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_DebuggerStep", SQLMan_Trace, 1);
    DBProc_Debugger* pDebugger = SQLMan_Context::AcvToContext(acv).GetDBProcDebugger();
    if (pDebugger)
    {
        pDebugger->step(count);
    }
}

//-------------------------------------------------------------------------

void a101_DebuggerStoreExecuteInfo (
    tsp00_MoveObjPtr                     pInfo,
    integer                              size)
{
    DBProc_Debugger::storeExecuteInfo (pInfo, size);
}

//-------------------------------------------------------------------------

void a101_DebuggerAddRemoveBreakPoint (
    tak_all_command_glob  VAR_VALUE_REF  acv,
    tgg00_Surrogate       VAR_ARRAY_REF  procId,
    integer                              procKind,
    integer                              type,
    integer                              pos,
    pasbool                              doRemove)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101DebuggerWaitForBreakPoint", SQLMan_Trace, 1);
    DBProc_Debugger* pDebugger = SQLMan_Context::AcvToContext(acv).GetDBProcDebugger();
    if (pDebugger)
    {
        pDebugger->addRemoveBreakPoint(procId, procKind, type, pos, 0 != doRemove);
    }
}

//-------------------------------------------------------------------------

void a101_DetachColumnBuffer (
    tak_all_command_glob  VAR_VALUE_REF  acv,
    tgg00_VoidPtr                        pTable)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_DetachColumnBuffer", SQLMan_Trace, 1);
    //SAPDBERR_ASSERT_STATE( a01SharedSqlEnabled );
    SQLMAN_UNPROTECT_ALLOCATOR(0);
    SQLMan_Context& context = SQLMan_Context::AcvToContext(acv);
    SharedSQL_SQLCache& sharedSQLCache = context.GetSharedSQL_SQLCache();
    REINTERPRET_CAST(Catalog_TableObject*, pTable)->DecColBufferRefCount(sharedSQLCache);
}

//-------------------------------------------------------------------------

tak_sysbufferaddress a101_DescribeParseId (
    tgg00_VoidPtr                        pExecuteHandle)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_DescribeParseId", SQLMan_Trace, 1);
    //SAPDBERR_ASSERT_STATE( a01SharedSqlEnabled );
    SQLMAN_UNPROTECT_ALLOCATOR (0);
    Catalog_SharedSqlObject::Catalog_Key key;
    SharedSQL_ExecuteHandle& executeHandle = *REINTERPRET_CAST (SharedSQL_ExecuteHandle*, pExecuteHandle);
    const void* p = executeHandle.GetPlan(&key);
    if (p)
    {
       const tsp00_C12& describeKey = REINTERPRET_CAST(const Catalog_SharedSqlObject*, p)->GetDescribeId();
       Catalog_Object::Catalog_Key resultKey(describeKey);
       p = executeHandle.GetPlan(&resultKey);
       if (p)
       {
         unsigned char* pChar = REINTERPRET_CAST(unsigned char*, CONST_CAST(void*, p)) + Catalog_SessionCache::ObjectHeader;
         return REINTERPRET_CAST(tak_sysbufferaddress, pChar);
       }
    }
    return NULL;
}

//-------------------------------------------------------------------------

pasbool a101_DropParseId (
    tak_all_command_glob  VAR_VALUE_REF  acv,
    tak_parsid            VAR_VALUE_REF  parsedId)
{
    // drops a parseid. Returns true (ok), if the parseid has been dropped successfully
    SAPDBTRACE_ROUTINE_DEBUG ("a101_DropParseId", SQLMan_Trace, 1);
    //SAPDBERR_ASSERT_STATE( a01SharedSqlEnabled );
    SQLMan_Context& context = SQLMan_Context::AcvToContext(acv);
	SharedSQL_SQLCache& sharedSQLCache = context.GetSharedSQL_SQLCache();

    SQLMAN_UNPROTECT_ALLOCATOR (sharedSQLCache.GetCommandCacheBaseRawAllocator());

    return (false == sharedSQLCache.DropParseID(*REINTERPRET_CAST(const SharedSQL_ParseID*, &parsedId)));
}

//-------------------------------------------------------------------------

void a101_SQLMan_ContextDestruct (tsp00_Addr& pAcv)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_SQLMan_ContextDestruct", SQLMan_Trace, 1);
    if (pAcv)
    {
        SQLMan_Context* pContext = REINTERPRET_CAST(SQLMan_Context*, pAcv);
        destroy (pContext, pContext->GetAllocator());
        pAcv = NULL;
    }
}

//-------------------------------------------------------------------------

void a101_DestroyContextMembers (tak_all_command_glob  VAR_VALUE_REF  acv)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_DestroyContextMembers", SQLMan_Trace, 1);
    SQLMAN_UNPROTECT_ALLOCATOR (0);
    SQLMan_Context::AcvToContext(acv).DestroyCppMembers();
}

//-------------------------------------------------------------------------

void a101_GetMySQLScramble (
    tsp00_C8              VAR_ARRAY_REF  scramble)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_GetMySQLScramble", SQLMan_Trace, 1);
    RTE_GetMySQLScramble(scramble);
}

//-------------------------------------------------------------------------

void a101_InitContextMembers (tak_all_command_glob  VAR_VALUE_REF  acv)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_InitContextMembers", SQLMan_Trace, 1);
    SQLMan_Context::AcvToContext(acv).InitCppMembers();
}

//-------------------------------------------------------------------------

externPascal void a101_InitSessionInfo (
    tak_all_command_glob  VAR_VALUE_REF  acv)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_InitSessionInfo", SQLMan_Trace, 1);
    
    SQLMan_Context& context = SQLMan_Context::AcvToContext(acv);
    context.GetSessionInfo().Init(context);
}

//-------------------------------------------------------------------------

externPascal void a101_SetSessionInfoIsolationLevel (
    tak_all_command_glob  VAR_VALUE_REF  acv,
    tsp00_Uint1                          isolationLevel)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_SetSessionInfoIsolationLevel", SQLMan_Trace, 1);
    
    SQLMan_Context& context = SQLMan_Context::AcvToContext(acv);
    context.GetSessionInfo().SetIsolationLevel(isolationLevel);
}

//-------------------------------------------------------------------------

pasbool a101_IsStatementActive (
    tak_all_command_glob  VAR_VALUE_REF  acv,
    tsp00_Int4                           statementId)
{
    return SQLMan_Context::AcvToContext(acv).IsStatementActive(statementId);
}

//-------------------------------------------------------------------------

void* a101_GetExecuteHandle (
     tak_all_command_glob  VAR_VALUE_REF  acv,
	 tak_parsid            VAR_VALUE_REF  parseId,
     pasbool               CountExecuting )
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_GetExecuteHandle", SQLMan_Trace, 1);
    //SAPDBERR_ASSERT_STATE( a01SharedSqlEnabled );
    SQLMan_Context& context = SQLMan_Context::AcvToContext(acv);
    SharedSQL_SQLCache& sharedSQLCache = context.GetSharedSQL_SQLCache();

    SQLMAN_UNPROTECT_ALLOCATOR (sharedSQLCache.GetCommandCacheBaseRawAllocator());
    
    SharedSQL_ParseID& ParseId      = *REINTERPRET_CAST(SharedSQL_ParseID*, &parseId);

    SQLMAN_SHARED_SQL_TRACE ("GetExecuteHandle " << ParseId);

    SAPDB_Bool Valid, minus9;
    SharedSQL_ExecuteHandle* pExecuteHandle = sharedSQLCache.NewExecuteHandle(context.GetAllocator(), ParseId, (CountExecuting?true:false), Valid, minus9);
	if (pExecuteHandle)
	{
        if (!Valid)
        {
            SQLMAN_SHARED_SQL_TRACE ("Plan invalid , -9 = " << ToStr(minus9));
            context.ThrowError (e_old_fileversion);
            return pExecuteHandle;
        }
		ParseId = *(pExecuteHandle->GetMasterParseID());
        SQLMAN_SHARED_SQL_TRACE ("Plan valid, master parseid = " << ParseId << " handle " << ToStr(pExecuteHandle));
	}
    else
    {
        SQLMAN_SHARED_SQL_TRACE ("no execute handle found");
    }
    return pExecuteHandle; 
}

//-------------------------------------------------------------------------

tgg00_VoidPtr a101_GetPlanElement (
    tgg00_VoidPtr                        pExecuteHandle,
    tgg00_SysInfoKey      VAR_VALUE_REF  key)
{
	SAPDBTRACE_ROUTINE_DEBUG ("a101_GetPlanElement", SQLMan_Trace, 1);
    //SAPDBERR_ASSERT_STATE( a01SharedSqlEnabled );

    SQLMAN_UNPROTECT_ALLOCATOR (0);
    void* p = CONST_CAST(void*, REINTERPRET_CAST (SharedSQL_ExecuteHandle*, pExecuteHandle)->GetPlan(&key));
	if (p)
	{
	    return REINTERPRET_CAST(unsigned char*, p) + Catalog_SessionCache::ObjectHeader;
	}
	else
	{
        //SQLMAN_SHARED_SQL_TRACE ("Plan element not found");
		return NULL;
	}
}

//-------------------------------------------------------------------------

void* a101_GetPrepareHandle (tak_all_command_glob  VAR_VALUE_REF  acv,
							   pasbool               VAR_VALUE_REF  isPrepared,
							   tak_parsid            VAR_VALUE_REF  masterParsedId,
                               tgg00_VoidPtr         VAR_VALUE_REF  pSegment,
                               integer               VAR_VALUE_REF  segmentLength)
{
	SAPDBTRACE_ROUTINE_DEBUG ("a101_GetPrepareHandle", SQLMan_Trace, 1);
    //SAPDBERR_ASSERT_STATE( a01SharedSqlEnabled );
    SQLMan_Context& context = SQLMan_Context::AcvToContext(acv);
    SharedSQL_SQLCache& sharedSQLCache = context.GetSharedSQL_SQLCache();
  
    SharedSQL_SQLContext  SQLContext(   acv.a_curr_user_id, // User
                                        acv.a_curr_user_id, // Schema
                                        acv.a_sqlmode,      // SQLMode
                                        acv.a_iso_level,    // IsolatioLevel
                                        acv.a_dt_format,    // DataTimeFormat
                                        acv.a_nls_params.date_format, 
                                        acv.a_nls_params.df_length, 
                                        acv.a_cmd_packet_header.sp1h_mess_code, // CodeType
                                        (acv.a_cmd_segment_header.sp1c_mass_cmd() ? true : false), // MassCommand
                                        false // VariableInput
                                    );

	pSegment      = NULL;
	segmentLength = 0;

    void* Description = 0;
    SAPDB_Int4 DescriptionSize = 0;
    if (acv.a_appl_param_part != NULL)
    {
        Description     = &acv.a_appl_param_part->sp1p_buf()[0];
        DescriptionSize = acv.a_appl_param_part->sp1p_buf_len();
    }
    SharedSQL_SQLStmt     Statement( &acv.a_cmd_part->sp1p_buf()[0], acv.a_cmd_part->sp1p_buf_len(), Description, DescriptionSize );

    SQLMAN_UNPROTECT_ALLOCATOR (sharedSQLCache.GetCommandCacheBaseRawAllocator());
    SAPDB_Bool Internal = (acv.a_in_ddl_trigger?true:false);
    SAPDB_Bool ParseAgain = (acv.a_parsing_again?true:false);
    SharedSQL_PrepareHandle* pHandle = sharedSQLCache.NewPrepareHandle(context.GetAllocator(), SQLContext, Statement, Internal, ParseAgain);
    if (pHandle)
    {
        SharedSQL_CommandStatus Status;
        isPrepared = (false == pHandle->MustPrepare(Status));
        // if isPrepared is TRUE the Status is Prepared
        // if isPrepared is FALSE the Status may be New, Invalid (due to DDL) or Dropped (due to out of memory)
        // In case of Dropped it may be possible to reparse without sendig -8/9 to the application
        SQLMAN_SHARED_SQL_TRACE ("Status " << ((Invalid == Status) ? "invalid" : 
            (Dropped == Status) ? "dropped" : (New == Status) ? "new" : (Preparing == Status) ? "preparing" : "prepared"));

        if (Status == Invalid || Status == Dropped)
        {
            // DDT: if Status == Dropped the command max be reparsed without notifying the client !!!
			const bool c_isRollback = true;
			a10_cache_delete (acv, !c_isRollback );
            acv.a_parsing_again = true;
        }
        else
        {
            if (isPrepared)
            {
                masterParsedId = *REINTERPRET_CAST(const tak_parsid*, pHandle->GetMasterParseID());
                SQLMAN_SHARED_SQL_TRACE ("GetPrepareHandle, master parseid = " << *pHandle->GetMasterParseID() << " handle " << ToStr(pHandle));
				Catalog_Object::Catalog_Key key;
				const Catalog_Object* pObject = REINTERPRET_CAST(const Catalog_Object*, pHandle->GetPlan(&key));
				if (pObject)
				{
					pSegment = CONST_CAST(void*, pObject->GetInfo(segmentLength));
				}
            }
        }
    }
    return pHandle;
}

/*----------------------------------------------------------------*/

void a101_GetStatement (
    tak_all_command_glob  VAR_VALUE_REF  acv,
    tgg00_VoidPtr                        pExecuteHandle,
    tsp00_MoveObjPtr      VAR_VALUE_REF  pStatement,
    integer               VAR_VALUE_REF  statementLength,
    tsp00_MoveObjPtr      VAR_VALUE_REF  pParamDescription,
    integer               VAR_VALUE_REF  paramDescLength,
    tsp00_SqlMode         VAR_VALUE_REF  sqlmode,
    pasbool               VAR_VALUE_REF  prepareFlag,
    pasbool               VAR_VALUE_REF  massCmdFlag)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_GetStatement", SQLMan_Trace, 1);
    const SharedSQL_ExecuteHandle* pHandle = REINTERPRET_CAST (const SharedSQL_ExecuteHandle*, pExecuteHandle);
    const SharedSQL_SQLContext* pSharedSQLContext;
    const SharedSQL_SQLStmt statement = pHandle->GetSQLStmt(pSharedSQLContext);
    pStatement        = REINTERPRET_CAST(tsp00_MoveObjPtr, statement.mStmt);    
    statementLength   = statement.mStmtSize;
    pParamDescription = REINTERPRET_CAST(tsp00_MoveObjPtr, statement.mDescription); 
    paramDescLength   = statement.mDescriptionSize;
    sqlmode.becomes(pSharedSQLContext->SQLMode);
    SAPDB_Bool minus9;
    pHandle->IsPlanValid(minus9);
    prepareFlag = minus9;
    massCmdFlag = pSharedSQLContext->MassCmd;
}

/*----------------------------------------------------------------*/

void a101_IncrementSyntaxTree (
    tak_all_command_glob  VAR_VALUE_REF  acv)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_IncrementSyntaxTree", SQLMan_Trace, 1);
    SQLMan_Context& context = SQLMan_Context::AcvToContext(acv);
    context.IncrementSyntaxTree();
}
 
/*----------------------------------------------------------------*/

void a101PacketError (
    tsp00_C50             VAR_ARRAY_REF  fmt,
    tsp00_Int4                           val1,
    tsp00_Int4                           val2,
    tsp00_Int4                           val3)
{
    int len = sizeof(fmt);
    while (' ' == fmt[len-1]) --len;
    char msg[51];
    memcpy (&msg[0], &fmt[0], len);
    msg[len] = 0;
    char opMsg[100];
    sp77sprintf (opMsg, sizeof(opMsg), msg, val1, val2, val3);
    {
        Kernel_OpError (csp3_structure_check, csp3_n_packet) << opMsg;
    }
    SQLMan_Context* pContext = SQLMan_Context::GetContext();
    pContext->ThrowError (e_invalid);
}

/*----------------------------------------------------------------*/

pasbool a101_PutParseId (
    tak_all_command_glob  VAR_VALUE_REF  acv, 
    tgg00_VoidPtr                        pPrepareHandle,
    tak_parsid            VAR_VALUE_REF  parseId)
{
	SAPDBTRACE_ROUTINE_DEBUG ("a101_PutParseId", SQLMan_Trace, 1);
    //SAPDBERR_ASSERT_STATE( a01SharedSqlEnabled );

	SharedSQL_PrepareHandle* cmdHandle  = REINTERPRET_CAST(SharedSQL_PrepareHandle*, pPrepareHandle);
	SQLMan_Context&           context    = SQLMan_Context::AcvToContext(acv);
	SharedSQL_SQLCache&      sharedSQLCache = context.GetSharedSQL_SQLCache();

    SQLMAN_UNPROTECT_ALLOCATOR (sharedSQLCache.GetCommandCacheBaseRawAllocator());

    SharedSQL_ParseID& ParseId = *REINTERPRET_CAST(SharedSQL_ParseID*, &parseId);
    SharedSQL_ModuleName Module;
    if (acv.a_modul_name != a01_il_b_identifier)
    {
        Module.mName = acv.a_modul_name;  
        Module.mSize = sizeof (acv.a_modul_name);
    }
    SQLMAN_SHARED_SQL_TRACE ("PutParseId " << ParseId);
    return sharedSQLCache.PutParseID(cmdHandle, ParseId, Module, (0 != acv.a_initial_segment_header.sp1c_prepare()));
}

/*----------------------------------------------------------------*/

void a101_GetModuleName (
    tak_all_command_glob    VAR_VALUE_REF acv,
    tak_parsid              VAR_VALUE_REF parseId,
    tgg00_VoidPtr           VAR_VALUE_REF NamePtr,
    tsp00_Int4              VAR_VALUE_REF Length)        
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_GetModuleName", SQLMan_Trace, 1);
    //SAPDBERR_ASSERT_STATE( a01SharedSqlEnabled );
 
    SQLMan_Context& Context = SQLMan_Context::AcvToContext(acv);
    SharedSQL_SQLCache& SharedSQLCache = Context.GetSharedSQL_SQLCache();
    SharedSQL_ParseID& ParseId = *REINTERPRET_CAST(SharedSQL_ParseID*, &parseId);

    NamePtr = NULL;
    Length  = 0;
    const SharedSQL_ModuleName* Module = SharedSQLCache.GetModuleName( ParseId );
    if ( Module )
    {
        NamePtr = Module->mName;
        Length  = Module->mSize;
    } 
}

/*----------------------------------------------------------------*/

pasbool a101_SetExecuteStatisticData (
    tak_all_command_glob  VAR_VALUE_REF  acv, 
    tak_parsid            VAR_VALUE_REF  parseId,
    tgg00_Surrogate       VAR_VALUE_REF  CmdID,
    tsp00_Int4                           ExecuteTimeSec,
    tsp00_Int4                           ExecuteTimeMicroSec,
    tsp00_Int4                           ReadRowCount,
    tsp00_Int4                           QualifiedRowCount,
    tsp00_Int4                           VirtualReadCount,
    tsp00_Int4                           PhysicalReadCount,
    tsp00_Int4                           FetchRowCount,
    tsp00_Int4                           SuspendCount,
    tsp00_Int4                           WaitCount)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_SetExecuteStatisticData", SQLMan_Trace, 1);
    //SAPDBERR_ASSERT_STATE( a01SharedSqlEnabled );
 
    SQLMan_Context& Context = SQLMan_Context::AcvToContext(acv);
    SharedSQL_SQLCache& SharedSQLCache = Context.GetSharedSQL_SQLCache();
    SharedSQL_ParseID& ParseId = *REINTERPRET_CAST(SharedSQL_ParseID*, &parseId);

    return SharedSQLCache.SetExecuteStatisticData(
            ParseId,  
            (SharedSQL_CommandID&) CmdID, // output parameter
            ExecuteTimeSec, ExecuteTimeMicroSec,
            ReadRowCount, QualifiedRowCount,
            VirtualReadCount, PhysicalReadCount, 
            FetchRowCount,
            SuspendCount, WaitCount);
}

/*----------------------------------------------------------------*/

void a101_ReleaseExecuteHandle (
    tak_all_command_glob  VAR_VALUE_REF  acv, 
    tgg00_VoidPtr         VAR_VALUE_REF  planHandle)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_ReleaseExecuteHandle", SQLMan_Trace, 1);
    //SAPDBERR_ASSERT_STATE( a01SharedSqlEnabled );
 
    SQLMan_Context& context = SQLMan_Context::AcvToContext(acv);
    SharedSQL_SQLCache& sharedSQLCache = context.GetSharedSQL_SQLCache();
    
    SQLMAN_UNPROTECT_ALLOCATOR (sharedSQLCache.GetCommandCacheBaseRawAllocator());

    SharedSQL_ExecuteHandle* pExecuteHandle = REINTERPRET_CAST(SharedSQL_ExecuteHandle*, planHandle);

    if ((csp_old_fileversion == acv.a_returncode) || ( csp_use_new_pars_info == acv.a_returncode)) 
    {
        // plan no longer executable
        SharedSQL_ParseID ParseId = *(pExecuteHandle->GetMasterParseID());
        SQLMAN_SHARED_SQL_TRACE ("SetPlanInvalid " << ParseId);
        pExecuteHandle->SetPlanInvalid();
    }
    SQLMAN_SHARED_SQL_TRACE ("ReleaseExecuteHandle " << ToStr(pExecuteHandle));

	pExecuteHandle->ReleaseHandle();                      
    sharedSQLCache.DestroyExecuteHandle(pExecuteHandle);
    planHandle = NULL; 
}

/*----------------------------------------------------------------*/

tsp00_Int4 a101_SetMaxParallelServers (
    tsp00_Int4  max)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_SetMaxParallelServers", SQLMan_Trace, 1);
    if (max > IOMan_IDataInfo::GetInstance().ConfiguredDataVolumes() - 1)
    {
        return IOMan_IDataInfo::GetInstance().ConfiguredDataVolumes() - 1;
    }
    else
    {
        return max > 0 ? max : 0;
    }
}

/*----------------------------------------------------------------*/

pasbool a101_StorePlan (tak_all_command_glob  VAR_VALUE_REF  acv, 
                     tak_parsid            VAR_VALUE_REF  parseId,
                     pasbool                              storePlan,
                     tgg00_VoidPtr                        pHandle)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_StorePlan", SQLMan_Trace, 1);
    //SAPDBERR_ASSERT_STATE( a01SharedSqlEnabled );

    SQLMAN_UNPROTECT_ALLOCATOR (sharedSQLCache.GetCommandCacheBaseRawAllocator());
    SQLMan_Context& context = SQLMan_Context::AcvToContext(acv);
    SharedSQL_PrepareHandle* pCmdHandle = REINTERPRET_CAST(SharedSQL_PrepareHandle*, pHandle);

    bool ok = context.IsOk();
    if (ok && storePlan)
    {
        SharedSQL_SQLCache& sharedSQLCache = context.GetSharedSQL_SQLCache();

        SQLMAN_SHARED_SQL_TRACE ("StorePlan " << SAPDBTrace_Hex(&parseId, sizeof(parseId)));
        ok = context.GetSessionCatalogCache().StorePlan(sharedSQLCache, pCmdHandle, 
            *REINTERPRET_CAST(SQLMan_ParseId*, &parseId), (0 != acv.a_initial_segment_header.sp1c_prepare()));
    }
    if (!ok || !storePlan)
    {
        if (!ok)
        {
            SAPDBErr_MessageList msg ("SQLManager", __CONTEXT__, SQLMAN_ERR_STORE_PLAN_FAILED);
            context.GetErrorList().AppendNewMessage(msg);
        }
        SQLMAN_SHARED_SQL_TRACE ("ErrorWhilePreparing");
        pCmdHandle->ErrorWhilePreparing();
    }
    return ok;
}

/*----------------------------------------------------------------*/

#if defined (KERNEL80)
externPascal void a101_StoreTable (
    tak_all_command_glob  VAR_VALUE_REF  acv,
    tak_baserecord        VAR_VALUE_REF  BaseRecord)
{
   REINTERPRET_CAST(Catalog_TableObject*, &BaseRecord)->outcopy(SQLMan_Context::AcvToContext(acv));
}
#endif

/*----------------------------------------------------------------*/


void a101_ReleasePrepareHandle (tak_all_command_glob  VAR_VALUE_REF  acv, 
                     tgg00_VoidPtr VAR_VALUE_REF          pHandle,
                     tsp00_Int4                           PrepareTimeSecs,
                     tsp00_Int4                           PrepareTimeMicroSecs)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_ReleasePrepareHandle", SQLMan_Trace, 1);
    //SAPDBERR_ASSERT_STATE( a01SharedSqlEnabled );

    SQLMan_Context& context = SQLMan_Context::AcvToContext(acv);
    SharedSQL_PrepareHandle* pCmdHandle = REINTERPRET_CAST(SharedSQL_PrepareHandle*, pHandle);

    SharedSQL_SQLCache& sharedSQLCache = context.GetSharedSQL_SQLCache();
    SQLMAN_UNPROTECT_ALLOCATOR (sharedSQLCache.GetCommandCacheBaseRawAllocator());    

    SQLMAN_SHARED_SQL_TRACE ("ReleasePrepareHandle " << ToStr(pCmdHandle));

    if (pCmdHandle)
    {
        if (!context.IsOk())
        {
            SQLMAN_SHARED_SQL_TRACE ("ErrorWhilePreparing");
            pCmdHandle->ErrorWhilePreparing();
        }
        pCmdHandle->ReleaseHandle(PrepareTimeSecs, PrepareTimeMicroSecs);
        sharedSQLCache.DestroyPrepareHandle(pCmdHandle);
    }
    pHandle = NULL;
}

/*----------------------------------------------------------------*/

void a101_CleanUpAll (tak_all_command_glob  VAR_VALUE_REF  acv)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_CleanUpAll", SQLMan_Trace, 1);

    SharedSQL_SQLCache& sharedSQLCache = SQLMan_Context::AcvToContext(acv).GetSharedSQL_SQLCache();
    SQLMAN_UNPROTECT_ALLOCATOR (sharedSQLCache.GetCommandCacheBaseRawAllocator());    
    sharedSQLCache.CleanUpAll();
}

/*----------------------------------------------------------------*/

void a101_InvalidateAll (tak_all_command_glob  VAR_VALUE_REF  acv)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_InvalidateAll", SQLMan_Trace, 1);

    if ( a101_SharedSQL_GetStatusParameter() )
    {
        SQLMan_Context& context = SQLMan_Context::AcvToContext(acv);
        SharedSQL_SQLCache& sharedSQLCache = context.GetSharedSQL_SQLCache();
        SQLMAN_UNPROTECT_ALLOCATOR (sharedSQLCache.GetCommandCacheBaseRawAllocator());    
        sharedSQLCache.Invalidate(true);
    }
}

void a101_SilentReparseAll (tak_all_command_glob  VAR_VALUE_REF  acv)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_SilentReparseAll", SQLMan_Trace, 1);
    if ( a101_SharedSQL_GetStatusParameter() )
    {
        SQLMan_Context& context = SQLMan_Context::AcvToContext(acv);
        SharedSQL_SQLCache& sharedSQLCache = context.GetSharedSQL_SQLCache();
        SQLMAN_UNPROTECT_ALLOCATOR (sharedSQLCache.GetCommandCacheBaseRawAllocator());
        sharedSQLCache.Invalidate(false);
    }
}

//-------------------------------------------------------------------------

//void a101_InvalidateSelective (tak_all_command_glob  VAR_VALUE_REF  acv)
//{
//    SAPDBTRACE_ROUTINE_DEBUG ("a101_InvalidateSelective", SQLMan_Trace, 1);
//    SQLMan_Context& context = SQLMan_Context::AcvToContext(acv);
//    SQLMan_SharedSQLInvalidateInfo* pInfo = reinterpret_cast<SQLMan_SharedSQLInvalidateInfo*>(context.a_invalidateList);
//    if ( pInfo )
//    {
//        if ( a101_SharedSQL_GetStatusParameter() && context.IsOk() )
//        {
//            SharedSQL_SQLCache& sharedSQLCache = context.GetSharedSQL_SQLCache();
//            SQLMAN_UNPROTECT_ALLOCATOR (sharedSQLCache.GetCommandCacheBaseRawAllocator());
//            pInfo->Invalidate(sharedSQLCache);
//        }
//        destroy (pInfo, context.GetAllocator());
//        context.a_invalidateList = 0;
//    }
//}

//-------------------------------------------------------------------------

//void a101_SilentReparseSelective (tak_all_command_glob  VAR_VALUE_REF  acv)
//{
//    SAPDBTRACE_ROUTINE_DEBUG ("a101_SilentReparseSelective", SQLMan_Trace, 1);
//
//    if ( a101_SharedSQL_GetStatusParameter() )
//    {
//        SQLMan_Context& context = SQLMan_Context::AcvToContext(acv);
//        SharedSQL_SQLCache& sharedSQLCache = context.GetSharedSQL_SQLCache();
//        SQLMAN_UNPROTECT_ALLOCATOR (sharedSQLCache.GetCommandCacheBaseRawAllocator());
//
//        // put the tables involved with this command.
////        Container_Vector<SharedSQL_Table> Tables(allocator);    // allocator = sharedSQLCache !
//        // ...
//        // DDT: fill the container here
//        // ...
//        sharedSQLCache.Invalidate(/*&Tables*/ 0, false);
//
//		// OR
//		// SharedSQL_Schema Schema;
//		//sharedSQLCache.SilentReparse(Schema);
//    }
//}

/*----------------------------------------------------------------*/

void a101_ResetSharedSQLStatistics (tak_all_command_glob  VAR_VALUE_REF  acv)
{
    SAPDBTRACE_ROUTINE_DEBUG ("a101_ResetSharedSQLStatistics", SQLMan_Trace, 1);

    SharedSQL_SQLCache& sharedSQLCache = SQLMan_Context::AcvToContext(acv).GetSharedSQL_SQLCache();
    SQLMAN_UNPROTECT_ALLOCATOR (sharedSQLCache.GetCommandCacheBaseRawAllocator());    

    sharedSQLCache.ResetCommandCacheInfo();
    sharedSQLCache.ResetCommandInfos();
}

/*----------------------------------------------------------------*/

//tsp00_Int4 a101_RegisterCurrentStatement (
//    tak_all_command_glob  VAR_VALUE_REF  acv)
//{
//    return SQLMan_Context::AcvToContext(acv).RegisterCurrentStatement();
//}
 
/*----------------------------------------------------------------*/
 
//void a101_UnregisterStatement (
//    tak_all_command_glob  VAR_VALUE_REF  acv,
//    tsp00_Int4                           statementId)
//{
//    SQLMan_Context::AcvToContext(acv).UnregisterStatement(statementId);
//}

/*----------------------------------------------------------------*/

tsp00_Int2 a07_return_code (
    tgg00_BasisError         b_err,
    tsp00_SqlMode_Param      sqlmode)
{
    return (SQLManErr_Interface::GetInstance().GetReturnCode(b_err, sqlmode));
}

/*----------------------------------------------------------------*/

void a071_getmessagetext (
    tsp00_Int2                           msgno,
    char*                                msgbuf,
    tsp00_Int2            VAR_VALUE_REF  msglen,
    pasbool               VAR_VALUE_REF  found)
{
    const char *msg = SQLManErr_Interface::GetInstance().GetErrorText(msgno);
    if (NULL == msg)
    {
        found = false;
        msglen = 0;
    }
    else
    {
        found = true;
        msglen = strlen (msg);
        memcpy (msgbuf, msg, msglen);
    }
}

/*----------------------------------------------------------------*/

void a071_nextmessagetext (
    tsp00_Int2            VAR_VALUE_REF  msgno,
    char*                                msgbuf,
    tsp00_Int2            VAR_VALUE_REF  msglen,
    pasbool               VAR_VALUE_REF  found)
{
    const char *msg = SQLManErr_Interface::GetInstance().GetNextText(&msgno);
    if (NULL == msg)
    {
        found = false;
        msglen = 0;
        return;
    }
    else
    {
        found = true;
        msglen = strlen (msg);
        memcpy (msgbuf, msg, msglen);
        return;
    }
}

/*----------------------------------------------------------------*/

externPascal SAPDB_Int4 a101_GetMaxJoinHashTableSize()
{
    return Join_HashAccessAllocator::Instance().GetMaxHashTableSize();
}

/*----------------------------------------------------------------*/


externPascal void a101_AddToSessionList (
    tak_all_command_glob  VAR_VALUE_REF  acv)
{
	SAPDBTRACE_ROUTINE_DEBUG ("a101_AddToSessionList",
                              SQLMan_Trace, 1);

    SQLMan_SessionList& sessionList = SQLMan_SessionList::Instance();
    SQLMan_Context& sqlContext = SQLMan_Context::AcvToContext(acv);

    SQLMan_SessionList::AddReturnCode rc = sessionList.Add(
        sqlContext, 
        sqlContext.GetErrorList());

    if ( rc != SQLMan_SessionList::arcOk ) {
        if ( rc == SQLMan_SessionList::arcOutOfMemory ) {
            a07_b_put_error (acv, e_no_more_memory, 1);
        }
    }            
}

/*----------------------------------------------------------------*/

externPascal void a101_RemoveFromSessionList (
    tak_all_command_glob  VAR_VALUE_REF  acv)
{
	SAPDBTRACE_ROUTINE_DEBUG ("a101_RemoveFromSessionList",
                              SQLMan_Trace, 1);

    SQLMan_SessionList& sessionList = SQLMan_SessionList::Instance();
    SQLMan_Context& sqlContext = SQLMan_Context::AcvToContext(acv);

    sessionList.Remove(
        sqlContext, 
        sqlContext.GetErrorList());
}

/*----------------------------------------------------------------*/
