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

  module      : Catalog_SessionCache.cpp

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

  responsible : ThomasA

  special area: Catalog
  description : encapsulation of pascal AK cache

  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 "SQLManager/Catalog/Catalog_SessionCacheInline.hpp"
#include "SQLManager/Catalog/Catalog_DBProcObject.hpp"
#include "SQLManager/Catalog/Catalog_DBProcFileObject.hpp"
#include "SQLManager/Catalog/Catalog_DBProcInfoObject.hpp"
#include "SQLManager/Catalog/Catalog_TableObject.hpp"
#include "SQLManager/Catalog/Catalog_MessBlockObject.hpp"
#include "SQLManager/Catalog/Catalog_SharedSqlObject.hpp"
#include "SQLManager/SharedSQL/SharedSQL_Handles.hpp"
#include "SQLManager/SharedSQL/SharedSQL_SQLCache.hpp"
#include "SQLManager/Catalog/Catalog_Messages.hpp"
#include "SQLManager/SQLMan_Tracing.hpp"

#include "hak01.h"
#include "hak10.h"
#include "hak260.h"

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


Catalog_SessionCache::Catalog_SessionCache(SQLMan_Context& context)
: m_context(context)
, m_lastError(0)
{
}

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

Catalog_SessionCache::LruIterator::LruIterator(SQLMan_Context& context)
: m_context(context)
{
    m_curr = context.a_sysdir.ci_cache_dir_header.cdir_ptr()->cd_lru_next().cdir_ptr();
	m_next = m_curr->cd_lru_next().cdir_ptr();
}

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

Catalog_SessionCache::LruIterator Catalog_SessionCache::Begin() const
{
   SAPDBTRACE_METHOD_DEBUG ("Catalog_SessionCache::Begin", SQLMan_Trace, 5);
   LruIterator iter(m_context);
   return iter;
}

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

void Catalog_SessionCache::DestroyPlanObject(SAPDBMem_IRawAllocator& allocator, void* p)
{
  Catalog_Object* pObject = REINTERPRET_CAST(Catalog_Object*, p);
  if (0 == pObject->KeyLength())
  {
	  // catalog object with header
	  pObject = REINTERPRET_CAST(Catalog_Object*, REINTERPRET_CAST(unsigned char*, p) + Catalog_SessionCache::ObjectHeader);
      SQLMAN_TRACE_BUFFER (Catalog_Trace, 5, "DestroyPlanObject", pObject->GetKey(),  pObject->KeyLength());
	  switch (pObject->Type())
	  {
	  case TYPE_RESULT:
	  case TYPE_TABLE :
		  {
			  Catalog_TableObject& Table = *pObject;
			  Table.DestroyColumns(allocator);
			  break;
		  }
	  case TYPE_MESSBLOCK :
		  {
			  Catalog_MessBlockObject& MessBlock = *pObject;
			  MessBlock.DestroyParts(allocator);
			  break;
		  }
	  }
  }
  allocator.Deallocate(p);
}

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

SAPDB_Int2 Catalog_SessionCache::GetLastError() const
{
    return m_lastError;
}

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

Catalog_Object* Catalog_SessionCache::Load (Catalog_Object::Catalog_Key & key)
{
    tak_sysbufferaddress p;
    a10get_sysinfo (m_context, key, d_fix, p, m_lastError);
    if (e_ok == m_lastError)
    {
        return REINTERPRET_CAST(Catalog_Object*, p);
    }
    return 0;
}

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

Catalog_MessBlockObject* Catalog_SessionCache::LoadCode(const SQLMan_Surrogate& procId)
{
    SAPDBTRACE_METHOD_DEBUG ("Catalog_SessionCache::LoadCode", Catalog_Trace, 1);
    Catalog_Object::Catalog_Key key;
    a260BuildCodeSyskey (procId, key);
    return REINTERPRET_CAST(Catalog_MessBlockObject*, this->Load(key));
}

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

Catalog_DBProcInfoObject* Catalog_SessionCache::LoadDBProcInfoObject(const SQLMan_Surrogate& procId)
{
    SAPDBTRACE_METHOD_DEBUG ("Catalog_SessionCache::LoadDBProcInfoObject", Catalog_Trace, 1);
    Catalog_DBProcInfoObject::Catalog_Key key(procId);
    return REINTERPRET_CAST(Catalog_DBProcInfoObject*, this->Load(key));
 }

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

Catalog_DBProcObject* Catalog_SessionCache::LoadDBProcObject(const SQLMan_Surrogate& procId)
{
    SAPDBTRACE_METHOD_DEBUG ("Catalog_SessionCache::LoadDBProcObject", Catalog_Trace, 1);
    Catalog_DBProcObject::Catalog_Key key(procId);
    return REINTERPRET_CAST(Catalog_DBProcObject*, this->Load(key));
 }

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

Catalog_DBProcFileObject* Catalog_SessionCache::LoadDBProcFileObject(const SQLMan_Surrogate& procId)
{
    SAPDBTRACE_METHOD_DEBUG ("Catalog_SessionCache::LoadDBProcFileObject", Catalog_Trace, 1);
    Catalog_DBProcFileObject::Catalog_Key key(procId);
    return REINTERPRET_CAST(Catalog_DBProcFileObject*, this->Load(key));
}

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

bool Catalog_SessionCache::StorePlan (SharedSQL_SQLCache&      sharedSQLCache, 
									  SharedSQL_PrepareHandle* cmdHandle, 
									  SQLMan_ParseId&           parseId,
                                      bool                      prepareFlag)
{
    SAPDBTRACE_METHOD_DEBUG ("Catalog_SessionCache::StorePlan", SQLMan_Trace, 5);
	SharedSQL_ParseID& PID = *REINTERPRET_CAST(SharedSQL_ParseID*, &parseId); 
    SAPDBMem_IRawAllocator& allocator = sharedSQLCache;
    // store the describe id
    tak_sysbufferaddress pDescId;
    tgg00_BasisError     e;
    a10find_result (m_context, parseId.pid_parsk(), d_release, pDescId, e);
    if (e_ok == e)
    {
        Catalog_SharedSqlObject* pSharedSqlObject = new(allocator) Catalog_SharedSqlObject(pDescId->syskey().sstandardkey()); 
        if (!pSharedSqlObject)
        {
            return false;
        }
        SQLMAN_TRACE_BUFFER(SQLMan_Trace, 5, "Put into plan", pSharedSqlObject, pSharedSqlObject->Length());
        if ( !cmdHandle->PutPlan (PID, pSharedSqlObject, pSharedSqlObject->Length()) )
        {
            SAPDBErr_MessageList msg ("Catalog", __CONTEXT__, CATALOG_ERR_STORE_PLAN_OBJECT_FAILED);
            m_context.GetErrorList().AppendNewMessage(msg);
            return false;
        }
    }
    // store all plan parts (records) created by the current command lying in the session cache
	for (LruIterator iter = Begin(); iter; ++iter)
    {
        if (iter()->cd_create_cmd_no() == m_context.GetCurrentCommandId())
        {
            if (!this->StorePlanObject (*iter.GetCatalogObject(), allocator, PID, cmdHandle))
            {
                return false;
            }
        }
    }
    // store all plan parts (records) created by the current command which have already been unloaded 
    // into the data cache
    Catalog_Object::Catalog_Key key;
    while (a10NextDisplacedKey (m_context, key)) 
    {
        Catalog_Object* pObj = this->Load(key);
        if (pObj)
        {
            if (!this->StorePlanObject (*pObj, allocator, PID, cmdHandle))
            {
                return false;
            }
        }
    }
	// store the return packet into plan
	int segmentLength       = m_context.a_return_segm->sp1s_segm_len();
	int offset              = Catalog_Object::DefaultOffset;
	Catalog_Object* pObject = REINTERPRET_CAST(Catalog_Object*, allocator.Allocate(offset + segmentLength));
	if (!pObject)
	{
		return false;
	}
    pObject = new(pObject) Catalog_Object(Catalog_Object::DefaultKeyLen, segmentLength);
    pObject->PutInfo(m_context.a_return_segm, segmentLength);
	SQLMAN_TRACE_BUFFER (SQLMan_Trace, 5, "put segment into plan :",  pObject, offset + segmentLength); 
	if ( !cmdHandle->PutPlan (PID, pObject, offset + segmentLength) )
    {
        SAPDBErr_MessageList msg ("Catalog", __CONTEXT__, CATALOG_ERR_STORE_PLAN_OBJECT_FAILED);
        m_context.GetErrorList().AppendNewMessage(msg);
        return false;
    }
 	// finally put the parse id
    parseId.pid_parsk().p_kind.becomes(m_sharedSQLParseid);

    SharedSQL_ModuleName Module;
    Module.mName = m_context.a_modul_name; 
    Module.mSize = sizeof(m_context.a_modul_name);
	sharedSQLCache.PutParseID(cmdHandle, PID, Module, prepareFlag);  // DDT: handle return code !!
	return true;
}

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

bool Catalog_SessionCache::StorePlanObject (
    Catalog_Object&             planObject,
    SAPDBMem_IRawAllocator&     allocator,
    SharedSQL_ParseID&          PID,
    SharedSQL_PrepareHandle*   cmdHandle
    )
{
    if ((TYPE_RESULTNAME == planObject.Type()) || (TYPE_TRIGGERPARSEINFO == planObject.Type()))
    {
        // don't copy these records, they are session local required only
        return true;
    }
    SAPDB_UInt4 memoryUsed;
    // this is a plan information of the current plan
    void* p = planObject.CreateCopy(allocator, Catalog_SessionCache::ObjectHeader, memoryUsed);
    if (p)
    {
        tgg00_BasisError e;
        SQLMAN_TRACE_BUFFER(SQLMan_Trace, 5, "Put into plan", p, Catalog_SessionCache::ObjectHeader + 20);
        // invalidate transaction of current plan info
        Catalog_Object::InvalidateTransaction(p, Catalog_SessionCache::ObjectHeader);
        // store plan info in shared sql manager
        if ( cmdHandle->PutPlan (PID, p, memoryUsed) )
        {
            // finally delete plan info from session cache
            a10del_sysinfo (m_context, planObject.syskey(), e);
            return true;
        }
        else
        {
            this->DestroyPlanObject(allocator, p);
        }
    }
    SAPDBErr_MessageList msg ("Catalog", __CONTEXT__, CATALOG_ERR_STORE_PLAN_OBJECT_FAILED);
    m_context.GetErrorList().AppendNewMessage(msg);
    return false;
}

