Added sharedDatabaseInterface and oci implementation libraries

This commit is contained in:
Anonymous
2014-01-14 22:29:01 -07:00
parent 8585710698
commit fe509b9480
108 changed files with 7603 additions and 0 deletions
@@ -0,0 +1,26 @@
set(SHARED_SOURCES
DbBindableVarray.cpp
DbBindableVarray.h
OciQueryImplementation.cpp
OciQueryImplementation.h
OciServer.cpp
OciServer.h
OciSession.cpp
OciSession.h
)
include_directories(
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedDebug/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundation/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundationTypes/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedLog/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMemoryManager/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedSynchronization/include/public
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/unicode/include
)
add_library(sharedDatabaseInterface_oci STATIC
${SHARED_SOURCES}
${PLATFORM_SOURCES}
)
@@ -0,0 +1,591 @@
// ======================================================================
//
// DbBindableVarray.cpp
// copyright (c) 2003 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "DbBindableVarray.h"
#include "OciServer.h"
#include "OciSession.h"
#include "sharedFoundation/NetworkId.h"
#include "sharedLog/Log.h"
#include <oci.h>
// ======================================================================
using namespace DB;
// ======================================================================
BindableVarray::BindableVarray() :
m_initialized(false),
m_tdo (NULL),
m_data (NULL),
m_session (NULL)
{
}
// ----------------------------------------------------------------------
BindableVarray::~BindableVarray()
{
if (m_initialized)
free();
}
// ----------------------------------------------------------------------
bool BindableVarray::create(DB::Session *session, const std::string &name, const std::string &schema)
{
m_initialized = true;
NOT_NULL(session);
m_session = session;
OCISession *localSession = safe_cast<OCISession*>(session);
if (! (localSession->m_server->checkerr(*localSession, OCITypeByName (localSession->envhp,
localSession->errhp,
localSession->svchp,
reinterpret_cast<OraText*>(const_cast<char*>(schema.c_str())),
schema.length(),
reinterpret_cast<OraText*>(const_cast<char*>(name.c_str())),
name.length(),
NULL,
0,
OCI_DURATION_SESSION,
OCI_TYPEGET_HEADER,
&m_tdo))))
return false;
if (! (localSession->m_server->checkerr(*localSession,
OCIObjectNew (localSession->envhp,
localSession->errhp,
localSession->svchp,
OCI_TYPECODE_VARRAY,
m_tdo, NULL,
OCI_DURATION_DEFAULT,
true,
reinterpret_cast<void**>(&m_data)))))
return false;
NOT_NULL(m_tdo);
NOT_NULL(m_data);
return true;
}
// ----------------------------------------------------------------------
void BindableVarray::free()
{
OCISession *localSession = safe_cast<OCISession*>(m_session);
IGNORE_RETURN(localSession->m_server->checkerr(*localSession,
OCIObjectFree (localSession->envhp,
localSession->errhp, m_data, 0)));
m_initialized = false;
m_tdo=NULL;
m_data=NULL;
m_session=NULL;
}
// ----------------------------------------------------------------------
void BindableVarray::clear()
{
OCISession *localSession = safe_cast<OCISession*>(m_session);
sb4 size=0;
if (! (localSession->m_server->checkerr(*localSession, OCICollSize(localSession->envhp, localSession->errhp, m_data, &size))))
return;
if (! (localSession->m_server->checkerr(*localSession, OCICollTrim(localSession->envhp, localSession->errhp, size, m_data))))
return;
}
// ----------------------------------------------------------------------
OCIArray** BindableVarray::getBuffer()
{
return &m_data;
}
// ----------------------------------------------------------------------
OCIType* BindableVarray::getTDO()
{
return m_tdo;
}
// ----------------------------------------------------------------------
bool BindableVarrayNumber::push_back(int value)
{
OCINumber buffer;
OCIInd buffer_indicator (OCI_IND_NOTNULL);
OCISession *localSession = safe_cast<OCISession*>(m_session);
if (! (localSession->m_server->checkerr(*localSession, OCINumberFromInt(localSession->errhp, &value, sizeof(value), OCI_NUMBER_SIGNED, &buffer))))
return false;
if (! (localSession->m_server->checkerr(*localSession, OCICollAppend(localSession->envhp, localSession->errhp, &buffer, &buffer_indicator, m_data))))
return false;
return true;
}
// ----------------------------------------------------------------------
bool BindableVarrayNumber::push_back(long int value)
{
OCINumber buffer;
OCIInd buffer_indicator (OCI_IND_NOTNULL);
OCISession *localSession = safe_cast<OCISession*>(m_session);
if (! (localSession->m_server->checkerr(*localSession, OCINumberFromInt(localSession->errhp, &value, sizeof(value), OCI_NUMBER_SIGNED, &buffer))))
return false;
if (! (localSession->m_server->checkerr(*localSession, OCICollAppend(localSession->envhp, localSession->errhp, &buffer, &buffer_indicator, m_data))))
return false;
return true;
}
// ----------------------------------------------------------------------
bool BindableVarrayNumber::push_back(int64 value)
{
OCINumber buffer;
OCIInd buffer_indicator (OCI_IND_NOTNULL);
OCISession *localSession = safe_cast<OCISession*>(m_session);
if (! (localSession->m_server->checkerr(*localSession, OCINumberFromInt(localSession->errhp, &value, sizeof(value), OCI_NUMBER_SIGNED, &buffer))))
return false;
if (! (localSession->m_server->checkerr(*localSession, OCICollAppend(localSession->envhp, localSession->errhp, &buffer, &buffer_indicator, m_data))))
return false;
return true;
}
// ----------------------------------------------------------------------
bool BindableVarrayNumber::push_back(double value)
{
if (finite(value)==0)
{
if (DB::Server::getFatalOnDataError())
{
FATAL(true,("DatabaseError: Attempt to save a non-finite value to the database."));
}
else
{
value=0;
WARNING_STACK_DEPTH(true,(INT_MAX,"DatabaseError: Attempt to save a non-finite value to the database."));
}
}
OCINumber buffer;
OCIInd buffer_indicator (OCI_IND_NOTNULL);
OCISession *localSession = safe_cast<OCISession*>(m_session);
if (! (localSession->m_server->checkerr(*localSession, OCINumberFromReal(localSession->errhp, &value, sizeof(value), &buffer))))
return false;
if (! (localSession->m_server->checkerr(*localSession, OCICollAppend(localSession->envhp, localSession->errhp, &buffer, &buffer_indicator, m_data))))
return false;
return true;
}
// ----------------------------------------------------------------------
bool BindableVarrayNumber::push_back(bool IsNULL, int value)
{
OCINumber buffer;
OCIInd buffer_indicator;
if ( IsNULL )
{
buffer_indicator = OCI_IND_NULL;
}
else
{
buffer_indicator = OCI_IND_NOTNULL;
}
OCISession *localSession = safe_cast<OCISession*>(m_session);
if (! (localSession->m_server->checkerr(*localSession, OCINumberFromInt(localSession->errhp, &value, sizeof(value), OCI_NUMBER_SIGNED, &buffer))))
return false;
if (! (localSession->m_server->checkerr(*localSession, OCICollAppend(localSession->envhp, localSession->errhp, &buffer, &buffer_indicator, m_data))))
return false;
return true;
}
// ----------------------------------------------------------------------
bool BindableVarrayNumber::push_back(bool IsNULL, long int value)
{
OCINumber buffer;
OCIInd buffer_indicator;
if ( IsNULL )
{
buffer_indicator = OCI_IND_NULL;
}
else
{
buffer_indicator = OCI_IND_NOTNULL;
}
OCISession *localSession = safe_cast<OCISession*>(m_session);
if (! (localSession->m_server->checkerr(*localSession, OCINumberFromInt(localSession->errhp, &value, sizeof(value), OCI_NUMBER_SIGNED, &buffer))))
return false;
if (! (localSession->m_server->checkerr(*localSession, OCICollAppend(localSession->envhp, localSession->errhp, &buffer, &buffer_indicator, m_data))))
return false;
return true;
}
// ----------------------------------------------------------------------
bool BindableVarrayNumber::push_back(bool IsNULL, int64 value)
{
OCINumber buffer;
OCIInd buffer_indicator;
if ( IsNULL )
{
buffer_indicator = OCI_IND_NULL;
}
else
{
buffer_indicator = OCI_IND_NOTNULL;
}
OCISession *localSession = safe_cast<OCISession*>(m_session);
if (! (localSession->m_server->checkerr(*localSession, OCINumberFromInt(localSession->errhp, &value, sizeof(value), OCI_NUMBER_SIGNED, &buffer))))
return false;
if (! (localSession->m_server->checkerr(*localSession, OCICollAppend(localSession->envhp, localSession->errhp, &buffer, &buffer_indicator, m_data))))
return false;
return true;
}
// ----------------------------------------------------------------------
bool BindableVarrayNumber::push_back(bool IsNULL, double value)
{
if (!IsNULL && finite(value)==0)
{
if (DB::Server::getFatalOnDataError())
{
FATAL(true,("DatabaseError: Attempt to save a non-finite value to the database."));
}
else
{
value=0;
WARNING_STACK_DEPTH(true,(INT_MAX,"DatabaseError: Attempt to save a non-finite value to the database."));
}
}
OCINumber buffer;
OCIInd buffer_indicator;
if ( IsNULL )
{
buffer_indicator = OCI_IND_NULL;
}
else
{
buffer_indicator = OCI_IND_NOTNULL;
}
OCISession *localSession = safe_cast<OCISession*>(m_session);
if (! (localSession->m_server->checkerr(*localSession, OCINumberFromReal(localSession->errhp, &value, sizeof(value), &buffer))))
return false;
if (! (localSession->m_server->checkerr(*localSession, OCICollAppend(localSession->envhp, localSession->errhp, &buffer, &buffer_indicator, m_data))))
return false;
return true;
}
// ======================================================================
BindableVarrayString::BindableVarrayString() :
BindableVarray(),
m_maxLength(0)
{
}
// ----------------------------------------------------------------------
std::string BindableVarrayNumber::outputValue() const
{
OCISession *localSession = safe_cast<OCISession*>(m_session);
sb4 size;
std::string result("[");
if (! (localSession->m_server->checkerr(*localSession, OCICollSize(localSession->envhp, localSession->errhp, m_data, &size))))
return "[*ERROR*]";
for (sb4 i=0; i < size; ++i)
{
OCINumber *element;
OCIInd *indicator;
boolean exists;
if (i!=0)
result += ", ";
if (localSession->m_server->checkerr(*localSession, OCICollGetElem(localSession->envhp, localSession->errhp, m_data, i, &exists, reinterpret_cast<dvoid**>(&element), reinterpret_cast<dvoid**>(&indicator))))
{
if (exists)
{
if (*indicator == OCI_IND_NULL)
result += "NULL";
else
{
double value;
if (localSession->m_server->checkerr(*localSession, OCINumberToReal(localSession->errhp, element, sizeof(value), &value)))
{
char buffer[100];
snprintf(buffer,sizeof(buffer),"%f",value);
buffer[sizeof(buffer)-1]='\0';
result += buffer;
}
else
result += "*ERROR*";
}
}
else
result += "*NO ELEMENT*";
}
else
result += "*ERROR*";
}
result+=']';
return result;
}
// ----------------------------------------------------------------------
bool BindableVarrayString::create(DB::Session *session, const std::string &name, const std::string &schema, size_t maxLength)
{
m_maxLength=maxLength;
return BindableVarray::create(session,name,schema);
}
// ----------------------------------------------------------------------
bool BindableVarrayString::push_back(const Unicode::String &value)
{
std::string str;
str = Unicode::wideToUTF8(value, str);
return push_back(str);
}
// ----------------------------------------------------------------------
bool BindableVarrayString::push_back(const std::string &value)
{
OCIString *buffer = NULL;
OCIInd buffer_indicator (OCI_IND_NOTNULL);
OCISession *localSession = safe_cast<OCISession*>(m_session);
size_t effectiveLength=value.length();
if (effectiveLength > m_maxLength)
{
if (DB::Server::getFatalOnDataError())
{
FATAL(true,("DatabaseError: Attempt to save too long a string to the database: \"%s\"",value.c_str()));
}
else
{
WARNING_STACK_DEPTH(true,(INT_MAX, "DatabaseError: Attempt to save too long a string to the database. (Text is in the log output.)"));
LogManager::logLongText("DatabaseError",std::string("String from previous error is \"")+value+"\"");
effectiveLength = m_maxLength;
}
}
if (! (localSession->m_server->checkerr(*localSession, OCIStringAssignText(localSession->envhp, localSession->errhp, reinterpret_cast<OraText*>(const_cast<char*>(value.c_str())), effectiveLength, &buffer))))
return false;
if (! (localSession->m_server->checkerr(*localSession, OCICollAppend(localSession->envhp, localSession->errhp, buffer, &buffer_indicator, m_data))))
return false;
return true;
}
// ----------------------------------------------------------------------
bool BindableVarrayString::push_back(bool bvalue)
{
std::string value;
if (bvalue)
value = "Y";
else
value = "N";
OCIString *buffer = NULL;
OCIInd buffer_indicator (OCI_IND_NOTNULL);
OCISession *localSession = safe_cast<OCISession*>(m_session);
if (! (localSession->m_server->checkerr(*localSession, OCIStringAssignText(localSession->envhp, localSession->errhp, reinterpret_cast<OraText*>(const_cast<char*>(value.c_str())), value.length(), &buffer))))
return false;
if (! (localSession->m_server->checkerr(*localSession, OCICollAppend(localSession->envhp, localSession->errhp, buffer, &buffer_indicator, m_data))))
return false;
return true;
}
// ----------------------------------------------------------------------
bool BindableVarrayString::push_back(const NetworkId &value)
{
return push_back(value.getValueString());
}
// ----------------------------------------------------------------------
bool BindableVarrayString::push_back(bool IsNULL, const Unicode::String &value)
{
std::string str;
str = Unicode::wideToUTF8(value, str);
return push_back(IsNULL, str);
}
// ----------------------------------------------------------------------
bool BindableVarrayString::push_back(bool IsNULL, const std::string &value)
{
OCIString *buffer = NULL;
OCIInd buffer_indicator;
if ( IsNULL )
{
buffer_indicator = OCI_IND_NULL;
}
else
{
buffer_indicator = OCI_IND_NOTNULL;
}
size_t effectiveLength=value.length();
if (effectiveLength > m_maxLength)
{
if (DB::Server::getFatalOnDataError())
{
FATAL(true,("DatabaseError: Attempt to save too long a string to the database: \"%s\"",value.c_str()));
}
else
{
WARNING_STACK_DEPTH(true,(INT_MAX, "DatabaseError: Attempt to save too long a string to the database. (Text is in the log output.)"));
LogManager::logLongText("DatabaseError",std::string("String from previous error is \"")+value+"\"");
effectiveLength = m_maxLength;
}
}
OCISession *localSession = safe_cast<OCISession*>(m_session);
if (! (localSession->m_server->checkerr(*localSession, OCIStringAssignText(localSession->envhp, localSession->errhp, reinterpret_cast<OraText*>(const_cast<char*>(value.c_str())), effectiveLength, &buffer))))
return false;
if (! (localSession->m_server->checkerr(*localSession, OCICollAppend(localSession->envhp, localSession->errhp, buffer, &buffer_indicator, m_data))))
return false;
return true;
}
// ----------------------------------------------------------------------
bool BindableVarrayString::push_back(bool IsNULL, bool bvalue)
{
std::string value;
if (bvalue)
value = "Y";
else
value = "N";
OCIString *buffer = NULL;
OCIInd buffer_indicator;
if ( IsNULL )
{
buffer_indicator = OCI_IND_NULL;
}
else
{
buffer_indicator = OCI_IND_NOTNULL;
}
OCISession *localSession = safe_cast<OCISession*>(m_session);
if (! (localSession->m_server->checkerr(*localSession, OCIStringAssignText(localSession->envhp, localSession->errhp, reinterpret_cast<OraText*>(const_cast<char*>(value.c_str())), value.length(), &buffer))))
return false;
if (! (localSession->m_server->checkerr(*localSession, OCICollAppend(localSession->envhp, localSession->errhp, buffer, &buffer_indicator, m_data))))
return false;
return true;
}
// ----------------------------------------------------------------------
bool BindableVarrayString::push_back(bool IsNULL, const NetworkId &value)
{
return push_back(IsNULL, value.getValueString());
}
// ----------------------------------------------------------------------
std::string BindableVarrayString::outputValue() const
{
OCISession *localSession = safe_cast<OCISession*>(m_session);
sb4 size;
std::string result("[");
if (! (localSession->m_server->checkerr(*localSession, OCICollSize(localSession->envhp, localSession->errhp, m_data, &size))))
return "[*ERROR*]";
for (sb4 i=0; i < size; ++i)
{
OCIString **element;
OCIInd *indicator;
boolean exists;
if (i!=0)
result += ", ";
if (localSession->m_server->checkerr(*localSession, OCICollGetElem(localSession->envhp, localSession->errhp, m_data, i, &exists, reinterpret_cast<dvoid**>(&element), reinterpret_cast<dvoid**>(&indicator))))
{
if (exists)
{
if (*indicator == OCI_IND_NULL)
result += "NULL";
else
{
OraText * text = OCIStringPtr(localSession->envhp, *element);
if (text)
result += '"' + std::string(reinterpret_cast<char*>(text)) + '"';
else
result += "NULL";
}
}
else
result += "*NO ELEMENT*";
}
else
result += "*ERROR*";
}
result+=']';
return result;
}
// ======================================================================
@@ -0,0 +1,101 @@
// ======================================================================
//
// DbBindableVarray.h
// copyright (c) 2003 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_DbBindableVarray_H
#define INCLUDED_DbBindableVarray_H
// ======================================================================
#include "sharedDatabaseInterface/Bindable.h"
// ======================================================================
struct OCIColl;
typedef OCIColl OCIArray;
struct OCIType;
class NetworkId;
// ======================================================================
namespace DB
{
class Session;
// ======================================================================
/**
* Bindable array type. Note: only usable in OCI. In ODBC, calling
* any function on this class will FATAL.
*/
class BindableVarray : public Bindable
{
public:
BindableVarray();
~BindableVarray();
bool create(DB::Session *session, const std::string &name, const std::string &schema);
void free();
void clear();
OCIArray ** getBuffer();
OCIType * getTDO();
protected:
bool m_initialized;
OCIType *m_tdo;
OCIArray *m_data;
Session *m_session;
};
// ======================================================================
class BindableVarrayNumber : public BindableVarray
{
public:
bool push_back(bool IsNULL, int value);
bool push_back(bool IsNULL, double value);
bool push_back(bool IsNULL, long int value);
bool push_back(bool IsNULL, int64 value);
bool push_back(int value);
bool push_back(double value);
bool push_back(long int value);
bool push_back(int64 value);
virtual std::string outputValue() const;
};
// ======================================================================
class BindableVarrayString : public BindableVarray
{
public:
BindableVarrayString();
bool create(DB::Session *session, const std::string &name, const std::string &schema, size_t maxLength);
bool push_back(bool IsNULL, const Unicode::String &value);
bool push_back(bool IsNULL, const std::string &value);
bool push_back(bool IsNULL, bool value);
bool push_back(bool IsNULL, const NetworkId &value);
bool push_back(const Unicode::String &value);
bool push_back(const std::string &value);
bool push_back(bool value);
bool push_back(const NetworkId &value);
virtual std::string outputValue() const;
private:
size_t m_maxLength;
};
// ======================================================================
} //namespace
// ======================================================================
#endif
@@ -0,0 +1,753 @@
// ======================================================================
//
// OCIQueryImpl.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "OciQueryImplementation.h"
#include <oci.h>
#include "sharedDatabaseInterface/Bindable.h"
#include "sharedDatabaseInterface/DbBindableVarray.h"
#include "sharedDatabaseInterface/DbProtocol.def"
#include "sharedDatabaseInterface/DbQuery.h"
#include "OciServer.h"
#include "OciSession.h"
#include "sharedLog/Log.h"
// ======================================================================
DB::OCIQueryImpl::OCIQueryImpl(Query *query, bool autocommit) :
QueryImpl(query), m_stmthp(0), m_cursorhp(0), m_procBind(0), m_session(0), m_server(0), m_inUse(false), numRowsFetched(0),
nextColumn(1), nextParameter(1), m_endOfData(false), m_dataReady(false), m_autocommit(autocommit),
m_skipSize(0),
m_numElements(1),
m_sql()
{
}
// ----------------------------------------------------------------------
DB::OCIQueryImpl::~OCIQueryImpl()
{
if (m_stmthp)
done();
for (BindRecListType::iterator i=bindRecList.begin(); i!=bindRecList.end(); ++i)
{
delete (*i);
}
}
// ----------------------------------------------------------------------
bool DB::OCIQueryImpl::setup(Session *session)
{
// setSession(session);
DEBUG_FATAL(m_session!=0,("m_session was not NULL"));
DEBUG_FATAL(m_server!=0,("m_server was not NULL"));
DEBUG_FATAL(m_stmthp!=0,("m_stmthp was not 0"));
DEBUG_FATAL(m_cursorhp!=0,("m_cursorhp was not 0"));
m_session=dynamic_cast<DB::OCISession*>(session);
FATAL((m_session==0),("Must pass a non-NULL OCISession to setup()."));
m_server=m_session->m_server;
NOT_NULL(m_server);
if (!m_server->checkerr(*m_session, OCIHandleAlloc( m_session->envhp,
reinterpret_cast<void**>(&m_stmthp),
OCI_HTYPE_STMT, 0, 0)))
return false;
m_cursorhp=m_stmthp; // later on, we'll separate these two if needed
return true;
}
// ----------------------------------------------------------------------
bool DB::OCIQueryImpl::prepare()
{
NOT_NULL(m_server);
NOT_NULL(m_stmthp);
m_query->getSQL(m_sql); // note: do not change m_sql until done() is called, because Oracle keeps a pointer to it
DEBUG_FATAL(m_sql.size()==0,("Query did not set a SQL statement.\n"));
if (!m_server->checkerr(*m_session,
OCIStmtPrepare(m_stmthp,
m_session->errhp,
reinterpret_cast<OraText*>(const_cast<char*>(m_sql.c_str())),
strlen(m_sql.c_str()),
(ub4) OCI_NTV_SYNTAX,
(ub4) OCI_DEFAULT)))
return false;
if (m_query->getMode()==Query::MODE_PLSQL_REFCURSOR)
{
m_cursorhp=0; // may not be necessary -- OCI docs unclear
if (!m_server->checkerr(*m_session, OCIHandleAlloc( m_session->envhp, (dvoid **) &m_cursorhp,
OCI_HTYPE_STMT, 0, 0)))
return false;
if (!m_server->checkerr(*m_session,
OCIBindByPos (m_stmthp,
&m_procBind,
m_session->errhp,
nextParameter++, // 1st parameter must be the cursor
&m_cursorhp,
0,
SQLT_RSET,
0,
0,
0,
0,
0,
OCI_DEFAULT)))
return false;
}
return true;
}
// ----------------------------------------------------------------------
void DB::OCIQueryImpl::preprocessBinds()
{
//Preprocess binds & defines
for (BindRecListType::iterator i=bindRecList.begin(); i!=bindRecList.end(); ++i)
{
if ((*i)->owner->isNull())
(*i)->indicator=-1;
else
{
(*i)->length=(unsigned short)*((*i)->owner->getIndicator()); //TODO: something better
(*i)->indicator=1;
if ((*i)->stringAdjust)
++(*i)->length; //TODO: This feels like a hack
}
}
}
// ----------------------------------------------------------------------
bool DB::OCIQueryImpl::exec()
{
NOT_NULL(m_server);
NOT_NULL(m_stmthp);
Query::QueryMode mode=m_query->getMode();
FATAL((mode!=Query::MODE_SQL) && (mode!=Query::MODE_DML) && (mode!=Query::MODE_PROCEXEC) && (mode!=Query::MODE_PLSQL_REFCURSOR),
("OCI query is in mode %i, not supported.\n",mode));
if (!m_inUse) // if the query was just run, we don't need to do the setup again
{
if (!prepare()) return false;
if (!m_query->bindParameters()) return false;
}
if (mode==Query::MODE_SQL)
if (!m_query->bindColumns()) return false;
preprocessBinds();
if (m_server->isPrefetchEnabled())
{
int numRowsToPrefetch=m_server->getPrefetchRows();
int prefetchMemory=m_server->getPrefetchMemory();
if (!m_server->checkerr(*m_session, OCIAttrSet((dvoid *) m_stmthp, (ub4) OCI_HTYPE_STMT,
&numRowsToPrefetch, sizeof(int),
(ub4) OCI_ATTR_PREFETCH_ROWS, m_session->errhp)))
{
LOG("DatabaseError", ("Unable to set OCI_ATTR_PREFETCH_ROWS to %i", numRowsToPrefetch));
return false;
}
if (!m_server->checkerr(*m_session, OCIAttrSet((dvoid *) m_stmthp, (ub4) OCI_HTYPE_STMT,
&prefetchMemory, sizeof(int),
(ub4) OCI_ATTR_PREFETCH_MEMORY, m_session->errhp)))
{
LOG("DatabaseError", ("Unable to set OCI_ATTR_PREFETCH_MEMORY to %i", prefetchMemory));
return false;
}
}
m_session->setOkToFetch();
m_session->setLastQueryStatement(m_sql);
sword status=OCIStmtExecute(m_session->svchp, m_stmthp, m_session->errhp, 1, 0,
NULL, NULL, OCI_DEFAULT);
if (status == OCI_NO_DATA)
{
if (mode==Query::MODE_PLSQL_REFCURSOR)
{
WARNING_STRICT_FATAL(!m_session->isOkToFetch(),("Calling fetch after commit, without an execute in between (may cause Oracle to crash)."));
sword status=OCIStmtFetch (m_cursorhp, m_session->errhp, 0, OCI_FETCH_NEXT, OCI_DEFAULT);
if (!m_server->checkerr(*m_session,status))
return false;
}
m_endOfData=true;
}
else
{
if (m_server->checkerr(*m_session,status))
{
if (mode==Query::MODE_PLSQL_REFCURSOR)
{
if (!m_query->bindColumns()) return false;
m_dataReady=false; // in this mode, Oracle doesn't implicitly fetch a row
m_endOfData=false;
}
else
{
postProcessResults(); // in this mode, Oracle implicitly fetches the first row
m_endOfData=false;
m_dataReady=true;
}
}
else
return false;
}
m_inUse=true;
return true;
}
// ----------------------------------------------------------------------
int DB::OCIQueryImpl::fetch()
{
DEBUG_FATAL((m_query->getMode()!=Query::MODE_SQL) && (m_query->getMode()!=Query::MODE_PLSQL_REFCURSOR),
("Called fetch() on a query not in a fetch-compatible mode."));
if (m_dataReady) // a row was already fetched implicitly by exec
{
m_dataReady = false;
return 1;
}
if (m_endOfData) return 0;
WARNING_STRICT_FATAL(!m_session->isOkToFetch(),("Calling fetch after commit, without an execute in between (may cause Oracle to crash)."));
sword status=OCIStmtFetch (m_cursorhp, m_session->errhp, m_numElements, OCI_FETCH_NEXT, OCI_DEFAULT);
if (status == OCI_NO_DATA)
{
ub4 rows;
ub4 sizep = sizeof(ub4);
OCIAttrGet((dvoid *) m_cursorhp, (ub4) OCI_HTYPE_STMT,
(dvoid *)& rows, (ub4 *) &sizep, OCI_ATTR_ROWS_FETCHED, m_session->errhp);
sword status=OCIStmtFetch (m_cursorhp, m_session->errhp, 0, OCI_FETCH_NEXT, OCI_DEFAULT); // cancel the cursor
if (!m_server->checkerr(*m_session,status))
return -1;
m_endOfData=true;
if (rows!=0)
{
postProcessResults();
return rows; // last batch of data
}
else
return 0; // no more data
}
else
{
if (!m_server->checkerr(*m_session,status))
return -1;
}
ub4 rows;
ub4 sizep = sizeof(ub4);
OCIAttrGet((dvoid *) m_cursorhp, (ub4) OCI_HTYPE_STMT,
(dvoid *)& rows, (ub4 *) &sizep, OCI_ATTR_ROWS_FETCHED, m_session->errhp);
m_endOfData=false;
postProcessResults();
return rows;
}
// ----------------------------------------------------------------------
void DB::OCIQueryImpl::postProcessResults()
{
if (m_numElements == 1)
{
for (BindRecListType::iterator i=bindRecList.begin(); i!=bindRecList.end(); ++i)
{
if ((*i)->indicator==-1)
(*i)->owner->setNull();
else
*((*i)->owner->getIndicator())=(*i)->length;
}
}
else
{
for (BindRecListType::iterator i=bindRecList.begin(); i!=bindRecList.end(); ++i)
{
if ((*i)->m_indicatorArray)
{
for (size_t j=0; j<m_numElements; ++j)
{
Bindable *owner = reinterpret_cast<Bindable*>(reinterpret_cast<char*>((*i)->owner) + m_skipSize * j); // if OCI can do something this ugly, so can I
if ((*i)->m_indicatorArray[j]==-1)
owner->setNull();
else
*(owner->getIndicator())=(*i)->m_lengthArray[j];
}
}
else
{
// this query involves bulk binds, but this parameter is not one of them. Treat it as a single bind.
if ((*i)->indicator==-1)
(*i)->owner->setNull();
else
*((*i)->owner->getIndicator())=(*i)->length;
}
}
}
}
// ----------------------------------------------------------------------
void DB::OCIQueryImpl::done()
{
NOT_NULL(m_stmthp);
if (m_autocommit)
m_server->checkerr(*m_session, OCITransCommit(m_session->svchp, m_session->errhp, 0));
OCIHandleFree(m_stmthp, OCI_HTYPE_STMT);
if (m_cursorhp!=m_stmthp)
OCIHandleFree(m_cursorhp, OCI_HTYPE_STMT);
for (BindRecListType::iterator i=bindRecList.begin(); i!=bindRecList.end(); ++i)
{
delete (*i);
}
bindRecList.clear();
m_session=0;
m_server=0;
m_stmthp=0;
m_cursorhp=0;
nextColumn=1;
nextParameter=1;
m_endOfData=true;
m_inUse=false;
}
// ----------------------------------------------------------------------
int DB::OCIQueryImpl::rowCount()
{
NOT_NULL(m_stmthp);
int value;
m_server->checkerr(*m_session, OCIAttrGet (m_cursorhp, OCI_HTYPE_STMT,&value,0,OCI_ATTR_ROW_COUNT,m_session->errhp));
return value;
}
// ----------------------------------------------------------------------
DB::OCIQueryImpl::BindRec *DB::OCIQueryImpl::addBindRec(Bindable &owner)
{
BindRec *br=new BindRec(m_numElements);
br->owner=&owner;
bindRecList.push_back(br);
return br;
}
// ----------------------------------------------------------------------
DB::Protocol DB::OCIQueryImpl::getProtocol() const
{
return DB::PROTOCOL_OCI;
}
// ----------------------------------------------------------------------
void DB::OCIQueryImpl::setColArrayMode(size_t skipSize, size_t numElements)
{
m_skipSize = skipSize;
m_numElements = numElements;
}
// ======================================================================
DB::OCIQueryImpl::BindRec::BindRec(size_t numElements) :
defnp(0),
bindp(0),
indicator(-1),
length(0),
stringAdjust(false),
m_numElements(numElements),
m_indicatorArray(NULL),
m_lengthArray(NULL)
{
// This is ugly, but it avoids having to create two different kinds of bindrecs that inherit from an abstract base class
if (m_numElements > 1)
{
m_indicatorArray = new int16[m_numElements];
m_lengthArray = new uint16[m_numElements];
}
}
// ----------------------------------------------------------------------
DB::OCIQueryImpl::BindRec::~BindRec()
{
delete[] m_indicatorArray;
delete[] m_lengthArray;
}
// ----------------------------------------------------------------------
int16 * DB::OCIQueryImpl::BindRec::getIndicatorPointer()
{
if (m_numElements > 1)
return m_indicatorArray;
else
return &indicator;
}
// ----------------------------------------------------------------------
uint16 * DB::OCIQueryImpl::BindRec::getLengthPointer()
{
if (m_numElements > 1)
return m_lengthArray;
else
return &length;
}
// ----------------------------------------------------------------------
size_t DB::OCIQueryImpl::BindRec::getIndicatorSkipSize()
{
return reinterpret_cast<char*>(&(m_indicatorArray[1])) - reinterpret_cast<char*>(&(m_indicatorArray[0]));
}
// ----------------------------------------------------------------------
size_t DB::OCIQueryImpl::BindRec::getLengthSkipSize()
{
return reinterpret_cast<char*>(&(m_lengthArray[1])) - reinterpret_cast<char*>(&(m_lengthArray[0]));
}
// ======================================================================
bool DB::OCIQueryImpl::bindCol(BindableLong &buffer)
{
BindRec *br=addBindRec(buffer);
m_server->checkerr(*m_session, OCIDefineByPos(m_cursorhp,
&(br->defnp),
m_session->errhp,
nextColumn++,
buffer.getBuffer(),
sizeof(long),
SQLT_INT,
br->getIndicatorPointer(),
br->getLengthPointer(),
(ub2 *)0,
OCI_DEFAULT));
if (m_numElements > 1)
{
m_server->checkerr(*m_session, OCIDefineArrayOfStruct(br->defnp,
m_session->errhp,
m_skipSize,
br->getIndicatorSkipSize(),
br->getLengthSkipSize(),
0));
}
return true;
}
// ----------------------------------------------------------------------
bool DB::OCIQueryImpl::bindParameter(BindableLong &buffer)
{
BindRec *br=addBindRec(buffer);
return m_server->checkerr(*m_session, OCIBindByPos (m_stmthp,
&(br->bindp),
m_session->errhp,
nextParameter++,
buffer.getBuffer(),
sizeof(long),
SQLT_INT,
&(br->indicator),
&(br->length),
0,
0,
0,
OCI_DEFAULT));
}
// ----------------------------------------------------------------------
bool DB::OCIQueryImpl::bindCol(BindableStringBase &buffer)
{
BindRec *br=addBindRec(buffer);
m_server->checkerr(*m_session, OCIDefineByPos(m_cursorhp,
&(br->defnp),
m_session->errhp,
nextColumn++,
buffer.getBuffer(),
buffer.getS()+1,
SQLT_STR,
br->getIndicatorPointer(),
br->getLengthPointer(),
(ub2 *)0,
OCI_DEFAULT));
if (m_numElements > 1)
{
m_server->checkerr(*m_session, OCIDefineArrayOfStruct(br->defnp,
m_session->errhp,
m_skipSize,
br->getIndicatorSkipSize(),
br->getLengthSkipSize(),
0));
}
return true;
}
// ----------------------------------------------------------------------
bool DB::OCIQueryImpl::bindParameter(BindableStringBase &buffer)
{
BindRec *br=addBindRec(buffer);
br->stringAdjust=true;
return m_server->checkerr(*m_session, OCIBindByPos (m_stmthp,
&(br->bindp),
m_session->errhp,
nextParameter++,
buffer.getBuffer(),
buffer.getS()+1,
SQLT_STR,
&(br->indicator),
&(br->length),
0,
0,
0,
OCI_DEFAULT));
}
// ----------------------------------------------------------------------
bool DB::OCIQueryImpl::bindCol(BindableUnicodeBase &buffer)
{
BindRec *br=addBindRec(buffer);
m_server->checkerr(*m_session, OCIDefineByPos(m_cursorhp,
&(br->defnp),
m_session->errhp,
nextColumn++,
buffer.getBuffer(),
buffer.getS()+1,
SQLT_STR,
br->getIndicatorPointer(),
br->getLengthPointer(),
(ub2 *)0,
OCI_DEFAULT));
if (m_numElements > 1)
{
m_server->checkerr(*m_session, OCIDefineArrayOfStruct(br->defnp,
m_session->errhp,
m_skipSize,
br->getIndicatorSkipSize(),
br->getLengthSkipSize(),
0));
}
return true;
}
// ----------------------------------------------------------------------
bool DB::OCIQueryImpl::bindParameter(BindableUnicodeBase &buffer)
{
BindRec *br=addBindRec(buffer);
br->stringAdjust=true;
br->length=static_cast<uint16>(*(buffer.getIndicator()));
return m_server->checkerr(*m_session, OCIBindByPos (m_stmthp,
&(br->bindp),
m_session->errhp,
nextParameter++,
buffer.getBuffer(),
buffer.getS()+1,
SQLT_STR,
&(br->indicator),
&(br->length),
0,
0,
0,
OCI_DEFAULT));
}
// ======================================================================
bool DB::OCIQueryImpl::bindCol(BindableDouble &buffer)
{
BindRec *br=addBindRec(buffer);
m_server->checkerr(*m_session, OCIDefineByPos(m_cursorhp,
&(br->defnp),
m_session->errhp,
nextColumn++,
buffer.getBuffer(),
sizeof(double),
SQLT_FLT,
br->getIndicatorPointer(),
br->getLengthPointer(),
(ub2 *)0,
OCI_DEFAULT));
if (m_numElements > 1)
{
m_server->checkerr(*m_session, OCIDefineArrayOfStruct(br->defnp,
m_session->errhp,
m_skipSize,
br->getIndicatorSkipSize(),
br->getLengthSkipSize(),
0));
}
return true;
}
// ----------------------------------------------------------------------
bool DB::OCIQueryImpl::bindParameter(BindableDouble &buffer)
{
BindRec *br=addBindRec(buffer);
return m_server->checkerr(*m_session, OCIBindByPos (m_stmthp,
&(br->bindp),
m_session->errhp,
nextParameter++,
buffer.getBuffer(),
sizeof(double),
SQLT_FLT,
&(br->indicator),
&(br->length),
0,
0,
0,
OCI_DEFAULT));
}
// ----------------------------------------------------------------------
bool DB::OCIQueryImpl::bindCol(BindableBool &buffer)
{
BindRec *br=addBindRec(buffer);
m_server->checkerr(*m_session, OCIDefineByPos(m_cursorhp,
&(br->defnp),
m_session->errhp,
nextColumn++,
buffer.getBuffer(),
2,
SQLT_STR,
br->getIndicatorPointer(),
br->getLengthPointer(),
(ub2 *)0,
OCI_DEFAULT));
if (m_numElements > 1)
{
m_server->checkerr(*m_session, OCIDefineArrayOfStruct(br->defnp,
m_session->errhp,
m_skipSize,
br->getIndicatorSkipSize(),
br->getLengthSkipSize(),
0));
}
return true;
}
// ----------------------------------------------------------------------
bool DB::OCIQueryImpl::bindParameter(BindableBool &buffer)
{
BindRec *br=addBindRec(buffer);
br->stringAdjust=true;
return m_server->checkerr(*m_session, OCIBindByPos (m_stmthp,
&(br->bindp),
m_session->errhp,
nextParameter++,
buffer.getBuffer(),
2,
SQLT_STR,
&(br->indicator),
&(br->length),
0,
0,
0,
OCI_DEFAULT));
}
// ----------------------------------------------------------------------
bool DB::OCIQueryImpl::bindParameter(BindableVarray &buffer)
{
BindRec *br=addBindRec(buffer);
bool result = m_server->checkerr(*m_session, OCIBindByPos (m_stmthp,
&(br->bindp),
m_session->errhp,
nextParameter++,
NULL,
0,
SQLT_NTY,
NULL,
NULL,
0,
0,
0,
OCI_DEFAULT));
if (!result)
return false;
return m_server->checkerr(*m_session, OCIBindObject (br->bindp,
m_session->errhp,
buffer.getTDO(),
reinterpret_cast<void**>(buffer.getBuffer()),
0,
0,
0));
}
// ----------------------------------------------------------------------
std::string DB::OCIQueryImpl::outputDataValues() const
{
std::string results;
for (BindRecListType::const_iterator i=bindRecList.begin(); i!=bindRecList.end(); ++i)
{
if (i!=bindRecList.begin())
results += ", ";
results += (*i)->owner->outputValue();
}
return results;
}
// ======================================================================
@@ -0,0 +1,133 @@
// ======================================================================
//
// OCIQueryImpl.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_OCIQueryImpl_H
#define INCLUDED_OCIQueryImpl_H
// ======================================================================
#include "sharedDatabaseInterface/DbQueryImplementation.h"
#include <list>
#include <string>
// ======================================================================
namespace DB
{
class BindableVarray;
}
// ======================================================================
struct OCIStmt;
struct OCIDefine;
struct OCIBind;
namespace DB
{
class Bindable;
class OCISession;
class OCIServer;
class OCIQueryImpl : public QueryImpl
{
public:
OCIQueryImpl(Query *query, bool autocommit);
virtual ~OCIQueryImpl();
virtual bool setup(Session *session);
virtual bool prepare();
virtual int fetch();
virtual void done();
virtual int rowCount();
virtual bool exec();
virtual Protocol getProtocol() const;
virtual void setColArrayMode(size_t skipSize, size_t numElements);
virtual bool bindCol(BindableLong &buffer);
virtual bool bindParameter(BindableLong &buffer);
virtual bool bindCol(BindableDouble &buffer);
virtual bool bindParameter(BindableDouble &buffer);
virtual bool bindCol(BindableStringBase &buffer);
virtual bool bindParameter(BindableStringBase &buffer);
virtual bool bindCol(BindableUnicodeBase &buffer);
virtual bool bindParameter(BindableUnicodeBase &buffer);
virtual bool bindCol(BindableBool &buffer);
virtual bool bindParameter(BindableBool &buffer);
virtual bool bindParameter(BindableVarray &buffer);
std::string outputDataValues() const;
protected:
struct BindRec
{
BindRec(size_t numElements);
~BindRec();
int16 * getIndicatorPointer();
uint16 * getLengthPointer();
size_t getIndicatorSkipSize();
size_t getLengthSkipSize();
Bindable *owner;
OCIDefine *defnp;
OCIBind *bindp;
int16 indicator;
uint16 length;
bool stringAdjust;
size_t m_numElements;
int16 *m_indicatorArray;
uint16 *m_lengthArray;
};
typedef std::list<BindRec*> BindRecListType;
protected:
BindRec *addBindRec(Bindable &owner);
void preprocessBinds();
void postProcessResults();
protected:
/** The OCIStmt handle representing the query.
*/
::OCIStmt *m_stmthp;
/** The handle representing the cursor containing the results of the query. Usually,
* this is set to the same as stmthp.
*/
::OCIStmt *m_cursorhp;
::OCIBind *m_procBind;
DB::OCISession *m_session;
DB::OCIServer *m_server;
bool m_inUse;
int numRowsFetched;
int nextColumn;
int nextParameter;
bool m_endOfData;
bool m_dataReady;
BindRecListType bindRecList;
bool m_autocommit;
size_t m_skipSize;
size_t m_numElements;
std::string m_sql;
private:
OCIQueryImpl(const OCIQueryImpl&);
OCIQueryImpl & operator = (const OCIQueryImpl &);
};
}
// ======================================================================
#endif
@@ -0,0 +1,113 @@
// ======================================================================
//
// OCIServer.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "OciServer.h"
#include "OciSession.h"
#include "sharedDatabaseInterface/DbException.h"
#include "sharedLog/Log.h"
#include <oci.h>
// ======================================================================
DB::OCIServer::OCIServer(const char *_dsn, const char *_uid, const char *_pwd, bool useMemoryManager) :
DB::Server(_dsn,_uid,_pwd, useMemoryManager)
{
}
// ----------------------------------------------------------------------
// Server destructor
DB::OCIServer::~OCIServer()
{
disconnect();
}
// ----------------------------------------------------------------------
DB::Session *DB::OCIServer::createSession()
{
return new DB::OCISession(this);
}
// ----------------------------------------------------------------------
bool DB::OCIServer::checkerr(OCISession const & session, int status)
{
switch (status)
{
case OCI_SUCCESS:
return true;
case OCI_SUCCESS_WITH_INFO:
REPORT_LOG(true,("Error - OCI_SUCCESS_WITH_INFO\n"));
LOG("DatabaseError", ("Unhandled database error."));
return false;
case OCI_NEED_DATA:
REPORT_LOG(true,("Error - OCI_NEED_DATA\n"));
LOG("DatabaseError", ("Unhandled database error."));
return false;
case OCI_NO_DATA:
REPORT_LOG(true,("Error - OCI_NODATA\n"));
LOG("DatabaseError", ("Unhandled database error."));
return false;
case OCI_ERROR:
{
text errbuf[512];
sb4 errcode = 0;
OCIErrorGet((dvoid *)(session.errhp), (ub4) 1, (text *) NULL, &errcode,
errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR);
WARNING(true,("Database error: %.*s",512,errbuf));
LOG("DatabaseError",("Database error: %.*s",512,errbuf));
FATAL(DB::Server::getFatalOnError() || session.getFatalOnError(),("Database error: %.*s",512,errbuf));
return false;
/*
switch (errcode)
{
case 1013:
FATAL(true,("Cancelled by user request (ctrl-c or kill signal).\n"));
break;
case 12541:
REPORT_LOG(true,("Database Error - %.*s\n", 512, errbuf));
return false;
default:
FATAL(true,("Unhandled Database Error - %.*s\n", 512, errbuf));
break;
}
*/
}
case OCI_INVALID_HANDLE:
REPORT_LOG(true,("Error - OCI_INVALID_HANDLE\n"));
LOG("DatabaseError", ("Unhandled database error - OCI_INVALID_HANDLE"));
return false;
case OCI_STILL_EXECUTING:
REPORT_LOG(true,("Error - OCI_STILL_EXECUTE\n"));
LOG("DatabaseError", ("Unhandled database error."));
return false;
case OCI_CONTINUE:
REPORT_LOG(true,("Error - OCI_CONTINUE\n"));
LOG("DatabaseError", ("Unhandled database error."));
return false;
default:
REPORT_LOG(true,("Error - unrecognized OCI error state\n"));
LOG("DatabaseError", ("Unhandled database error."));
return false;
}
return false;
}
// ======================================================================
@@ -0,0 +1,53 @@
// ======================================================================
//
// OCIServer.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_OCIServer_H
#define INCLUDED_OCIServer_H
#include "sharedDatabaseInterface/DbServer.h"
// ======================================================================
struct OCIEnv;
struct OCIError;
struct OCIServer;
struct OCISvcCtx;
namespace DB {
class OCISession;
class OCIServer : public Server
{
public:
OCIServer(const char *_dsn, const char *_uid, const char *_pwd, bool useMemoryManager);
virtual ~OCIServer();
virtual Session *createSession();
/** Check the results from an ODBC call to identify whether the call succeeded. Returns TRUE if everything is OK, i.e.
the call returned SQL_SUCCESS, or it returned SQL_SUCCESS_WITH_INFO and the additional information does not indicate
a problem.
*/
// static bool checkError(int rc, SQLSMALLINT handleType, SQLHANDLE handle);
static bool checkerr(OCISession const & session, int status);
private:
// OCI requires sharing so many handles at different levels that it's easiest to just make everybody friends.
friend class OCISession;
friend class OCIQueryImpl;
OCIServer(const OCIServer &);
OCIServer & operator = (const OCIServer &);
};
}
// ======================================================================
#endif
@@ -0,0 +1,289 @@
// ======================================================================
//
// OCISession.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "OciSession.h"
#include "OciQueryImplementation.h"
#include "OciServer.h"
#include "sharedDatabaseInterface/DbException.h"
#include "sharedFoundation/Os.h"
#include "sharedLog/Log.h"
#include "sharedSynchronization/RecursiveMutex.h"
#include <oci.h>
#include <time.h>
// ======================================================================
namespace DB
{
namespace OCISessionNamespace
{
RecursiveMutex connectLock;
}
}
using namespace DB::OCISessionNamespace;
// ======================================================================
static dvoid *mallocHook(dvoid *, size_t size)
{
return reinterpret_cast<dvoid *>(new char[size]);
}
// ----------------------------------------------------------------------
static dvoid *reallocHook(dvoid *, dvoid *memptr, size_t newsize)
{
return reinterpret_cast<dvoid *>(MemoryManager::reallocate(memptr, newsize));
}
// ----------------------------------------------------------------------
static void freeHook(dvoid *, dvoid *memptr)
{
if (memptr)
delete [] reinterpret_cast<char *>(memptr);
}
// ======================================================================
DB::OCISession::OCISession(DB::OCIServer *server) :
m_server(server),
envhp(NULL),
errhp(NULL),
srvhp(NULL),
sesp(NULL),
svchp(NULL),
autoCommitMode(true),
m_resetTime(server->getReconnectTime()==0 ? 0 : time(0) + server->getReconnectTime()),
m_okToFetch(true)
{
}
DB::OCISession::~OCISession()
{
if (connected)
disconnect();
}
bool DB::OCISession::connect()
{
connectLock.enter();
// Create OCI environment. We're creating one environment per session,
// so that each session can be used by a different thread concurrently.
sword result=OCI_ERROR;
if (m_server->getUseMemoryManager())
{
result = OCIEnvCreate(&envhp, // OCIEnv **envhpp,
OCI_THREADED | OCI_OBJECT, //ub4 mode, //TODO: do we have to use threaded mode?
0, // CONST dvoid *ctxp,
&mallocHook, // CONST dvoid *(*malocfp)
// (dvoid *ctxp,
// size_t size),
&reallocHook, // CONST dvoid *(*ralocfp)
// (dvoid *ctxp,
// dvoid *memptr,
// size_t newsize),
&freeHook, // CONST void (*mfreefp)
// (dvoid *ctxp,
// dvoid *memptr))
0, //size_t xtramemsz,
0 ); //dvoid **usrmempp );
}
else
{
result = OCIEnvCreate(&envhp, // OCIEnv **envhpp,
OCI_THREADED | OCI_OBJECT, //ub4 mode, //TODO: do we have to use threaded mode?
0, // CONST dvoid *ctxp,
0, // CONST dvoid *(*malocfp)
// (dvoid *ctxp,
// size_t size),
0, // CONST dvoid *(*ralocfp)
// (dvoid *ctxp,
// dvoid *memptr,
// size_t newsize),
0, // CONST void (*mfreefp)
// (dvoid *ctxp,
// dvoid *memptr))
0, //size_t xtramemsz,
0 ); //dvoid **usrmempp );
}
FATAL(result != OCI_SUCCESS,("OciEnvCreate failed with error code %hd",result));
// Create error handle.
OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR,
(size_t) 0, (dvoid **) 0);
// Create handle to the server and establish connection
OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, OCI_HTYPE_SERVER,
(size_t) 0, (dvoid **) 0);
int retryCount = 0;
connected = false;
while (!connected && retryCount < 5)
{
LOG("DatabaseConnect", ("calling OCIServerAttach() for OCISession=[%p] with dsn=[%s], uid=[%s], pwd=[%s]", this, m_server->getDSN(), m_server->uid, m_server->pwd));
connected = DB::OCIServer::checkerr(*this,
OCIServerAttach( srvhp, errhp, reinterpret_cast<OraText*>(const_cast<char*>(m_server->getDSN())), strlen(m_server->getDSN()), 0));
if (! connected)
{
++retryCount;
DEBUG_REPORT_LOG(retryCount<5,("Retrying database connection\n"));
Os::sleep(1000);
}
}
if (!connected)
{
LOG("DatabaseError", ("Database error, Failed to connect to database after 5 tries"));
disconnect(); // cleanup
connectLock.leave();
return false;
}
// Create a session, set userid & password
OCIHandleAlloc(envhp, (void**) &sesp,
(ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0);
OCIAttrSet((dvoid *) sesp, (ub4) OCI_HTYPE_SESSION,
(dvoid *) m_server->uid, strlen(m_server->uid),
(ub4) OCI_ATTR_USERNAME, errhp);
OCIAttrSet((dvoid *) sesp, (ub4) OCI_HTYPE_SESSION,
(dvoid *) m_server->pwd, strlen(m_server->pwd),
(ub4) OCI_ATTR_PASSWORD, errhp);
// create service context (Wtf is a service context? Don't know, but you gotta have one.)
OCIHandleAlloc( envhp, (dvoid **) &svchp, OCI_HTYPE_SVCCTX,
(size_t) 0, (dvoid **) 0);
// Service context has pointers to Server and Session
OCIAttrSet( (dvoid *) svchp, OCI_HTYPE_SVCCTX, srvhp,
(ub4) 0, OCI_ATTR_SERVER, errhp);
OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX,
(dvoid *) sesp, (ub4) 0,
(ub4) OCI_ATTR_SESSION, errhp);
// Establish session (i.e. check password)
if (DB::OCIServer::checkerr(*this, OCISessionBegin ( svchp, errhp, sesp, OCI_CRED_RDBMS, (ub4) OCI_DEFAULT)))
{
connected=true;
}
else
{
disconnect(); // cleanup
connected=false;
}
connectLock.leave();
return connected;
}
bool DB::OCISession::disconnect()
{
connectLock.enter();
bool success = true;
connected=false;
if (srvhp && errhp && !DB::OCIServer::checkerr(*this,OCIServerDetach( srvhp, errhp, OCI_DEFAULT)))
{
LOG("DatabaseError", ("OCIDetach returned an error."));
success = false;
}
if (svchp && (OCIHandleFree(svchp,OCI_HTYPE_SVCCTX) != OCI_SUCCESS))
{
LOG("DatabaseError", ("OCIHandleFree OCI_HTYPE_SVCCTX returned an error."));
success = false;
}
if (sesp && (OCIHandleFree(sesp,OCI_HTYPE_SESSION) != OCI_SUCCESS))
{
LOG("DatabaseError", ("OCIHandleFree OCI_HTYPE_SESSION returned an error."));
success = false;
}
if (srvhp && (OCIHandleFree(srvhp,OCI_HTYPE_SERVER) != OCI_SUCCESS))
{
LOG("DatabaseError", ("OCIHandleFree OCI_HTYPE_SERVER returned an error."));
success = false;
}
if (errhp && (OCIHandleFree(errhp,OCI_HTYPE_ERROR) != OCI_SUCCESS))
{
LOG("DatabaseError", ("OCIHandleFree OCI_HTYPE_ERROR returned an error."));
success = false;
}
if (envhp && (OCIHandleFree(envhp,OCI_HTYPE_ENV) != OCI_SUCCESS))
{
LOG("DatabaseError", ("OCIHandleFree OCI_HTYPE_ENV returned an error."));
success = false;
}
svchp = NULL;
sesp = NULL;
srvhp = NULL;
errhp = NULL;
envhp = NULL;
connectLock.leave();
return success;
}
bool DB::OCISession::setAutoCommitMode(bool autocommit)
{
autoCommitMode=autocommit;
return true;
}
bool DB::OCISession::commitTransaction()
{
m_okToFetch = false;
return m_server->checkerr(*this, OCITransCommit(svchp, errhp, 0));
}
bool DB::OCISession::rollbackTransaction()
{
return m_server->checkerr(*this, OCITransRollback(svchp, errhp, 0));
}
bool DB::OCISession::reset()
{
autoCommitMode = true;
if (m_resetTime !=0 && time(0) > m_resetTime)
{
LOG("Reconnections",("Reconnecting"));
commitTransaction(); // just to be safe -- there shouldn't be an oustanding transaction now anyway
disconnect();
connect();
m_resetTime = time(0) + m_server->getReconnectTime();
}
return true;
}
DB::QueryImpl *DB::OCISession::createQueryImpl(Query *owner) const
{
return new DB::OCIQueryImpl(owner, autoCommitMode);
}
void DB::OCISession::setOkToFetch()
{
m_okToFetch = true;
}
// ======================================================================
@@ -0,0 +1,76 @@
// ======================================================================
//
// OCISession.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_OCISession_H
#define INCLUDED_OCISession_H
// ======================================================================
#include "sharedDatabaseInterface/DbSession.h"
struct OCIEnv;
struct OCIError;
struct OCIServer;
struct OCISession;
struct OCISvcCtx;
namespace DB {
class OCIServer; // not to be confused with ::OCIServer
class OCISession : public Session
{
OCIServer *m_server;
::OCIEnv *envhp;
::OCIError *errhp;
::OCIServer *srvhp;
::OCISession *sesp;
::OCISvcCtx *svchp;
bool autoCommitMode;
time_t m_resetTime;
bool m_okToFetch;
// following are disallowed:
OCISession(const OCISession& rhs);
OCISession &operator=(const OCISession& rhs);
public:
OCISession(OCIServer *server);
virtual ~OCISession();
virtual bool connect();
virtual bool disconnect();
virtual bool reset();
virtual bool setAutoCommitMode(bool autocommit);
virtual bool commitTransaction();
virtual bool rollbackTransaction();
virtual QueryImpl *createQueryImpl(Query *owner) const;
void setOkToFetch();
bool isOkToFetch() const;
// OCI requires sharing so many handles at different levels that it's easiest to just make everybody friends.
friend class OCIQueryImpl;
friend class OCIServer;
friend class BindableVarray;
friend class BindableVarrayNumber;
friend class BindableVarrayString;
};
}
// ======================================================================
inline bool DB::OCISession::isOkToFetch() const
{
return m_okToFetch;
}
// ======================================================================
#endif