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
+1
View File
@@ -2,6 +2,7 @@
add_subdirectory(sharedCollision)
add_subdirectory(sharedCommandParser)
add_subdirectory(sharedCompression)
add_subdirectory(sharedDatabaseInterface)
add_subdirectory(sharedDebug)
add_subdirectory(sharedFile)
add_subdirectory(sharedFoundation)
@@ -0,0 +1,12 @@
cmake_minimum_required(VERSION 2.8)
project(sharedDatabaseInterface)
if(WIN32)
add_definitions(/D_CRT_SECURE_NO_WARNINGS)
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/public)
add_subdirectory(src)
add_subdirectory(src_oci)
@@ -0,0 +1 @@
#include "../../src/shared/core/Bindable.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/BindableImplementation.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/BindableNetworkId.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/BufferString.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/DbBatchQuery.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/DbBindableBase.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/DbBindableBitArray.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/DbBindableBool.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/DbBindableDouble.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/DbBindableInt64.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/DbBindableLong.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/DbBindableString.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/DbBindableUnicode.h"
@@ -0,0 +1 @@
#include "../../src_oci/DbBindableVarray.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/DbBufferRow.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/DbException.h"
@@ -0,0 +1 @@
#include "../../src/shared/logger/DbLogEvent.h"
@@ -0,0 +1 @@
#include "../../src/shared/logger/DbLogger.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/DbModeQuery.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/DbProfiler.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/DbProtocol.def"
@@ -0,0 +1 @@
#include "../../src/shared/core/DbQuery.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/DbQueryImplementation.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/DbRow.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/DbServer.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/DbSession.h"
@@ -0,0 +1 @@
#include "../../src/shared/queue/DbTaskQueue.h"
@@ -0,0 +1 @@
#include "../../src/shared/queue/DbTaskRequest.h"
@@ -0,0 +1 @@
#include "../../src/shared/logger/DbTaskSaveLog.h"
@@ -0,0 +1 @@
#include "../../src/shared/queue/DbTestQuery.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/FirstSharedDatabaseInterface.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/NullEncodedStandardString.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/NullEncodedUnicodeString.h"
@@ -0,0 +1,7 @@
#if defined(PLATFORM_WIN32)
#include "../../src/win32/SQLC_Defs.h"
#elif defined(PLATFORM_LINUX)
#include "../../src/linux/SQLC_Defs.h"
#else
#error unsupported platform
#endif
@@ -0,0 +1,94 @@
set(SHARED_SOURCES
shared/core/Bindable.cpp
shared/core/Bindable.h
shared/core/BindableImplementation.h
shared/core/BindableNetworkId.cpp
shared/core/BindableNetworkId.h
shared/core/BufferString.cpp
shared/core/BufferString.h
shared/core/DbBatchQuery.h
shared/core/DbBindableBase.cpp
shared/core/DbBindableBase.h
shared/core/DbBindableBitArray.cpp
shared/core/DbBindableBitArray.h
shared/core/DbBindableBool.cpp
shared/core/DbBindableBool.h
shared/core/DbBindableDouble.cpp
shared/core/DbBindableDouble.h
shared/core/DbBindableInt64.cpp
shared/core/DbBindableInt64.h
shared/core/DbBindableLong.cpp
shared/core/DbBindableLong.h
shared/core/DbBindableString.cpp
shared/core/DbBindableString.h
shared/core/DbBindableUnicode.cpp
shared/core/DbBindableUnicode.h
shared/core/DbBufferRow.cpp
shared/core/DbBufferRow.h
shared/core/DbException.cpp
shared/core/DbException.h
shared/core/DbModeQuery.cpp
shared/core/DbModeQuery.h
shared/core/DbProfiler.cpp
shared/core/DbProfiler.h
shared/core/DbProtocol.def
shared/core/DbQuery.cpp
shared/core/DbQuery.h
shared/core/DbQueryImplementation.h
shared/core/DbRow.cpp
shared/core/DbRow.h
shared/core/DbServer.cpp
shared/core/DbServer.h
shared/core/DbSession.cpp
shared/core/DbSession.h
shared/core/FirstSharedDatabaseInterface.h
shared/core/NullEncodedUnicodeString.cpp
shared/core/NullEncodedUnicodeString.h
shared/core/NullEncodedStandardString.cpp
shared/core/NullEncodedStandardString.h
shared/logger/DbLogEvent.cpp
shared/logger/DbLogEvent.h
shared/logger/DbLogger.cpp
shared/logger/DbLogger.h
shared/logger/DbTaskSaveLog.cpp
shared/logger/DbTaskSaveLog.h
shared/queue/DbTaskQueue.cpp
shared/queue/DbTaskQueue.h
shared/queue/DbTestQuery.cpp
shared/queue/DbTestQuery.h
shared/queue/DbTaskRequest.cpp
shared/queue/DbTaskRequest.h
)
if(WIN32)
set(PLATFORM_SOURCES
win32/FirstSharedDatabaseInterface.cpp
win32/SQLC_Defs.h
)
else()
set(PLATFORM_SOURCES
linux/SQLC_Defs.h
)
endif()
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/shared
${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_ENGINE_SOURCE_DIR}/shared/library/sharedThread/include/public
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/archive/include
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/unicode/include
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/unicodeArchive/include/public
)
add_library(sharedDatabaseInterface STATIC
${SHARED_SOURCES}
${PLATFORM_SOURCES}
)
@@ -0,0 +1,18 @@
/* SQLC_Defs.h
*
* This file includes common definitions needed by the other SQLClasses header files.
* (Don't include this file directly -- files that require it will include it.)
*
* Note that this file is specific to each OS, because what header files are
* needed varies in each OS. In particular, Unix versions don't want windows.h.
*
* ODBC versions: includes definitions of ODBC datatypes needed by the various
* SQLClasses
*/
#ifndef _SQLC_DEFS_H
#define _SQLC_DEFS_H
#include <sqltypes.h>
#endif
@@ -0,0 +1,11 @@
// ======================================================================
//
// Bindable.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/Bindable.h"
// ======================================================================
@@ -0,0 +1,30 @@
/* Bindable.h
*
* Defines classes based on built-in simple types that know how to bind themselves to
* database queries and support null values.
*
* Each class supports the following functions:
* bool isNull -- test whether the value is null
* void setToNull -- set the value to null
* getValue -- return the value (make sure you test for null before calling this. The results
* are undefined if the Bindable is null.)
* setValue -- set the value
*
* ODBC version
*
* Including this header brings in all the bindable types.
*/
#ifndef _BINDABLE_H
#define _BINDABLE_H
#include "sharedDatabaseInterface/DbBindableBase.h"
#include "sharedDatabaseInterface/DbBindableBitArray.h"
#include "sharedDatabaseInterface/DbBindableBool.h"
#include "sharedDatabaseInterface/DbBindableDouble.h"
#include "sharedDatabaseInterface/DbBindableInt64.h"
#include "sharedDatabaseInterface/DbBindableLong.h"
#include "sharedDatabaseInterface/DbBindableString.h"
#include "sharedDatabaseInterface/DbBindableUnicode.h"
#endif
@@ -0,0 +1,34 @@
// ======================================================================
//
// BindableImpl.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_BindableImpl_H
#define INCLUDED_BindableImpl_H
// ======================================================================
namespace DB
{
class Bindable;
class BindableImpl
{
public:
BindableImpl(Bindable *owner);
virtual ~BindableImpl();
virtual bool isNull() const =0;
virtual void setNull() =0;
protected:
Bindable *m_owner;
};
}
// ======================================================================
#endif
@@ -0,0 +1,32 @@
// ======================================================================
//
// BindableNetworkId.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/BindableNetworkId.h"
using namespace DB;
// ======================================================================
BindableNetworkId::BindableNetworkId()
{
}
// ----------------------------------------------------------------------
BindableNetworkId::BindableNetworkId (const NetworkId &rhs) : BindableInt64(rhs.getValue())
{
}
// ----------------------------------------------------------------------
void BindableNetworkId::setValue(const NetworkId &buffer)
{
BindableInt64::setValue(buffer.getValue());
}
// ======================================================================
@@ -0,0 +1,75 @@
// ======================================================================
//
// BindableNetworkId.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_BindableNetworkId_H
#define INCLUDED_BindableNetworkId_H
// ======================================================================
#include "sharedDatabaseInterface/DbBindableInt64.h"
#include "sharedFoundation/NetworkId.h"
// ======================================================================
namespace DB
{
/**
* A Bindable type for an object Id.
* This class is intended to provide a layer between NetworkId and
* the database type, so that if the implementation of NetworkId is
* changed, only this class and the database schema need to be changed.
*
* Also, this class allows the code for persisting NetworkId's to follow
* the same form as the code persisting other types.
*/
class BindableNetworkId:public BindableInt64
{
public:
BindableNetworkId (const NetworkId &rhs);
BindableNetworkId();
BindableNetworkId &operator=(const NetworkId &rhs);
void getValue(NetworkId &buffer) const;
NetworkId getValue() const;
void setValue(const NetworkId &buffer);
};
}
// ======================================================================
inline DB::BindableNetworkId &DB::BindableNetworkId::operator=(const NetworkId &rhs)
{
BindableInt64::setValue(rhs.getValue());
return *this;
}
// ----------------------------------------------------------------------
inline void DB::BindableNetworkId::getValue(NetworkId &buffer) const
{
if (isNull())
buffer.m_value = NetworkId::cms_invalid.getValue();
else
buffer.m_value = BindableInt64::getValue();
}
// ----------------------------------------------------------------------
inline NetworkId DB::BindableNetworkId::getValue() const
{
if (isNull())
return NetworkId::cms_invalid;
else
return NetworkId(BindableInt64::getValue());
}
// ======================================================================
#endif
@@ -0,0 +1,157 @@
// ======================================================================
//
// BufferString.cpp
// copyright (c) 2004 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/BufferString.h"
#include "UnicodeUtils.h"
#include "sharedDatabaseInterface/DbServer.h"
#include "sharedDatabaseInterface/NullEncodedStandardString.h"
#include "sharedDatabaseInterface/NullEncodedUnicodeString.h"
#include "sharedLog/Log.h"
using namespace DB;
// ======================================================================
BufferString::BufferString(size_t maxSize) :
Bindable(),
m_value(),
m_maxSize(maxSize)
{
}
// ----------------------------------------------------------------------
void BufferString::getValue(std::string & value) const
{
if (isNull())
value.clear();
else
value=m_value;
}
// ----------------------------------------------------------------------
void BufferString::getValue(Unicode::String & value) const
{
if (isNull())
value.clear();
else
value=Unicode::utf8ToWide(m_value);
}
// ----------------------------------------------------------------------
Unicode::String BufferString::getValue() const
{
static const Unicode::String empty;
if (isNull())
return empty;
else
return Unicode::utf8ToWide(m_value);
}
// ----------------------------------------------------------------------
BufferString & BufferString::operator=(const std::string & value)
{
setValue(value);
return *this;
}
// ----------------------------------------------------------------------
BufferString & BufferString::operator=(const Unicode::String & value)
{
setValue(value);
return *this;
}
// ----------------------------------------------------------------------
void BufferString::setValue(const std::string & value)
{
if (value.size() > m_maxSize)
{
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+"\"");
m_value=std::string(value,0,m_maxSize);
}
}
else
m_value=value;
indicator=m_value.size();
}
// ----------------------------------------------------------------------
void BufferString::setValue(const Unicode::String & value)
{
setValue(Unicode::wideToUTF8(value));
}
// ----------------------------------------------------------------------
const std::string & BufferString::getValueASCII() const
{
static const std::string empty;
if (isNull())
return empty;
else
return m_value;
}
// ----------------------------------------------------------------------
BufferString & BufferString::operator=(const NullEncodedUnicodeString & value)
{
return operator=(value.getValueEncoded());
}
// ----------------------------------------------------------------------
void BufferString::getValue(NullEncodedUnicodeString & value) const
{
Unicode::String temp;
getValue(temp);
value.setValueEncoded(temp);
}
// ----------------------------------------------------------------------
BufferString & BufferString::operator=(const NullEncodedStandardString & value)
{
return operator=(value.getValueEncoded());
}
// ----------------------------------------------------------------------
void BufferString::getValue(NullEncodedStandardString & value) const
{
std::string temp;
getValue(temp);
value.setValueEncoded(temp);
}
// ----------------------------------------------------------------------
std::string BufferString::outputValue() const
{
return m_value;
}
// ======================================================================
@@ -0,0 +1,80 @@
// ======================================================================
//
// DbBufferString.h
// copyright (c) 2004 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_DbBufferString_H
#define INCLUDED_DbBufferString_H
// ======================================================================
#include "sharedDatabaseInterface/DbBindableBase.h"
#include "sharedDatabaseInterface/DbBindableString.h"
#include "sharedDatabaseInterface/DbBindableUnicode.h"
// ======================================================================
class NullEncodedUnicodeString;
class NullEncodedStandardString;
// ======================================================================
namespace DB
{
/**
* A nullable string class similar to DB::BindableString, but uses std::string
* internally. Unlike DB::BindableString, it does not allocate the maximum
* size for the buffer if the data is shorter. This class will save memory
* over DB::BindableString if used in a buffer that stores a lot of rows.
* However, it cannot be bound directly in a query. It must be copied
* to a varray or a DB::BindableString first.
*/
class BufferString : public Bindable
{
public:
BufferString(size_t maxSize);
template<int S>
BufferString(const BindableString<S> & rhs)
{
rhs.getValue(m_value);
indicator=m_value.size();
}
template<int S>
BufferString(const BindableUnicode<S> & rhs)
{
m_value = Unicode::wideToUTF8(rhs.getValue());
indicator=m_value.size();
}
public:
void getValue(std::string & value) const;
void getValue(Unicode::String & value) const;
void getValue(NullEncodedUnicodeString & value) const;
void getValue(NullEncodedStandardString & value) const;
Unicode::String getValue() const;
const std::string & getValueASCII() const;
BufferString & operator=(const std::string & value);
BufferString & operator=(const Unicode::String & value);
BufferString & operator=(const NullEncodedUnicodeString & value);
BufferString & operator=(const NullEncodedStandardString & value);
void setValue(const std::string & value);
void setValue(const Unicode::String & value);
virtual std::string outputValue() const;
private:
std::string m_value;
size_t m_maxSize;
};
// ======================================================================
} // namespace
// ======================================================================
#endif
@@ -0,0 +1,122 @@
/* DBBatchQuery.h
*
* Templates for defining batch queries (queries that return multiple
* rows, read from the database in batches). See SQLClasses
* documentation for more details.
*
* ODBC version
*/
#ifndef _DBBATCHQUERY_H
#define _DBBATCHQUERY_H
#include "sharedDatabaseInterface/DbQuery.h"
namespace DB {
/** Template representing a Query that returns an array of data
The template parameter R represent the structure that holds the data of one
row of the results. BatchQuery will contain an array of R's. (R will
usually be a struct holding a few Bindable types.)
*/
template <class R>
class BatchQuery : public Query
{
R *data;
SQLUSMALLINT *rowStatus;
int numRows;
public:
BatchQuery(int _numRows);
~BatchQuery();
bool bind();
const R &operator[](int index) const;
R &operator[](int index);
/** Count how many rows in the array were filled in by the last call to
Fetch().
*/
int getNumDefinedRows() const;
/** Is a particular row in the result array defined? A row is defined if the
database filled it in with values. If a row is not defined, the values
returned for that row by operator[] are not meaningful.
*/
bool isRowDefined(int index) const;
/** Returns the SQL string for the query. The user must define this function; the
template does not create it.
*/
char *getSQL();
/** Bind the first row of data. The user must define this function; the template
does not create it.
Implement this function as if it is binding the first element of the array
(the array is called data). The template will take care of binding the rest of
the array. It should contain something like
data[0].member.BindCol(1,this)
*/
bool bindFirstRow();
};
template <class R>
BatchQuery<R>::BatchQuery(int _numRows) : numRows(_numRows)
{
data = new R[numRows];
rowStatus = new SQLUSMALLINT[numRows];
}
template <class R>
BatchQuery<R>::~BatchQuery()
{
delete[] data;
delete[] rowStatus;
}
template <class R>
const R &BatchQuery<R>::operator[](int index) const
{
return data[index];
}
template <class R>
R &BatchQuery<R>::operator[](int index)
{
return data[index];
}
template <class R>
int BatchQuery<R>::getNumDefinedRows() const
// TODO: hmmm, might be better to figure this once and store it
// in a mutable variable -- but how to know when it changes
// without overriding Fetch()?
{
for (int num=numRows;num>0;--num)
{
if (isRowDefined(num))
return num+1;
}
return 0;
}
template <class R>
bool BatchQuery<R>::isRowDefined(int index) const
{
return (rowStatus[index]==0);
}
template <class R>
bool BatchQuery<R>::bind()
{
if (!setArrayMode(sizeof(data[0]),numRows,rowStatus))
return false;
return bindFirstRow();
}
}
#endif
@@ -0,0 +1,55 @@
// ======================================================================
//
// DBBindableBase.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbBindableBase.h"
// ======================================================================
using namespace DB;
// ----------------------------------------------------------------------
Bindable::Bindable() : indicator(-1)
{
}
// ----------------------------------------------------------------------
Bindable::~Bindable()
{
}
// ----------------------------------------------------------------------
Bindable::Bindable(int _indicator) :
indicator(_indicator)
{
}
// ----------------------------------------------------------------------
bool Bindable::isNull() const
{
return (indicator==-1);
}
// ----------------------------------------------------------------------
void Bindable::setNull()
{
indicator=-1;
}
// ----------------------------------------------------------------------
int *Bindable::getIndicator()
{
return &indicator; //lint !e1536 // Exposing private member. This is done because various functions in the DB interfaces want to set the indicator directly.
}
// ======================================================================
@@ -0,0 +1,43 @@
// ======================================================================
//
// DBBindableBase.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_DBBindableBase_H
#define INCLUDED_DBBindableBase_H
// ======================================================================
namespace DB {
class Bindable
{
public:
Bindable();
//Bindable(const Bindable &rhs); // auto-generated version is fine
//Bindable &operator=(const Bindable &rhs);
virtual ~Bindable();
bool isNull() const;
void setNull();
int *getIndicator(); //TODO: enforce that only QueryImpl uses this
virtual std::string outputValue() const = 0; // For debugging or reporting errors, output the value(s) stored in this Bindable object
protected:
explicit Bindable(int _indicator);
/**
* The size of the data, or -1 for NULL.
*/
int indicator;
};
}
// ======================================================================
#endif
@@ -0,0 +1,13 @@
// ======================================================================
//
// DbBindableBitArray.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbBindableBitArray.h"
// ======================================================================
// ======================================================================
@@ -0,0 +1,114 @@
// ======================================================================
//
// DBBindableBitArray.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_DBBindableBitArray_H
#define INCLUDED_DBBindableBitArray_H
// ======================================================================
#include "sharedDatabaseInterface/DbBindableString.h"
#include "sharedFoundation/BitArray.h"
// ======================================================================
namespace DB {
/**
* Bindable BitArray class
*
* Template parameter S is the maximum size of the BitArray
* The BitArray will be stored in the database using (S+3)/4 chars
* Each char is a hex value for 4 bits from the BitArray
*/
template<int S>
class BindableBitArray : public BindableString<int((S+3)>>2)>
{
public:
BindableBitArray();
explicit BindableBitArray(const BitArray &bitArray);
void setValue(const BitArray &bitArray);
BindableBitArray &operator=(const BitArray &bitArray);
void getValue(BitArray &bitArray) const;
BitArray getValue() const;
};
// ----------------------------------------------------------------------
template<int S>
BindableBitArray<S>::BindableBitArray()
{
}
// ----------------------------------------------------------------------
template<int S>
BindableBitArray<S>::BindableBitArray(const BitArray &bitArray)
{
setValue(bitArray);
}
// ----------------------------------------------------------------------
template<int S>
void BindableBitArray<S>::setValue(const BitArray &bitArray)
{
std::string buf;
bitArray.getAsDbTextString(buf, int((S+3)>>2));
// if no bits are set in the BitArray, we must
// put a character into buf, because BindableString
// won't save an empty string; empty string means
// don't overwrite current value in DB
if (buf.empty())
buf.push_back('0');
BindableString<int((S+3)>>2)>::setValue(buf);
}
// ----------------------------------------------------------------------
template<int S>
BindableBitArray<S> &BindableBitArray<S>::operator=(const BitArray &bitArray)
{
setValue(bitArray);
return *this;
}
// ----------------------------------------------------------------------
template<int S>
void BindableBitArray<S>::getValue(BitArray &bitArray) const
{
bitArray=getValue();
}
// ----------------------------------------------------------------------
template<int S>
BitArray BindableBitArray<S>::getValue() const
{
// Each char in the string is a hex value from 0-F
char buf[((S+3)>>2) + 1];
BindableString<int((S+3)>>2)>::getValue(buf,((S+3)>>2));
BitArray temp;
// indicator is the number of chars read from the database
if (indicator > 0)
{
buf[indicator] = 0;
temp.setFromDbTextString(buf);
}
return temp;
}
} // end namespace DB
// ======================================================================
#endif
@@ -0,0 +1,70 @@
// ======================================================================
//
// DBBindableBool.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbBindableBool.h"
// ======================================================================
using namespace DB;
BindableBool::BindableBool() : Bindable()
{
value[1]='\0';
}
BindableBool::BindableBool(bool _value) :
Bindable(1)
{
value[0]=_value?'Y':'N';
value[1]='\0';
}
std::string BindableBool::getValueASCII() const
{
if (isNull())
{
return std::string(); // TODO should this be defaulted to N
}
else
{
return std::string(1,value[0]);
}
}
bool BindableBool::getValue() const
{
return (value[0]=='Y');
}
void BindableBool::setValue(bool _value)
{
indicator=1;
value[0]=_value?'Y':'N';
}
BindableBool &BindableBool::operator=(bool _value)
{
setValue(_value);
return *this;
}
void *BindableBool::getBuffer()
{
return value; //lint !e1536 // exposing private member (because DB interface will set it directly)
}
std::string BindableBool::outputValue() const
{
if (getValue())
return std::string("true");
else
return std::string("false");
}
// ======================================================================
@@ -0,0 +1,58 @@
// ======================================================================
//
// DBBindableBool.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_DBBindableBool_H
#define INCLUDED_DBBindableBool_H
// ======================================================================
#include "sharedDatabaseInterface/DbBindableBase.h"
#include <string>
// ======================================================================
namespace DB {
/** Represents a bool in C++, bound to a CHAR(1) column. The column can have the values 'Y' or 'N'.
* TODO: use a boolean type in the database, if we can find one that allows NULL's and is fairly
* portable. (May not exist -- according to the docs, Oracle does not have a boolean datatype.)
*/
class BindableBool : public Bindable
{
char value[2];
public:
explicit BindableBool(bool _value);
BindableBool();
std::string getValueASCII() const;
bool getValue() const;
void getValue(bool &buffer) const;
void setValue(bool _value);
BindableBool &operator=(bool _value);
void *getBuffer();
virtual std::string outputValue() const;
}; //lint !e1721 !e1509 // no virtual destructor, unusual operator =
}
// ----------------------------------------------------------------------
/**
* There are places where it's more convenient to have a getValue() that
* takes a reference, for consistancy with more complicated types.
*/
inline void DB::BindableBool::getValue(bool &buffer) const
{
buffer=getValue();
}
// ======================================================================
#endif
@@ -0,0 +1,83 @@
// ======================================================================
//
// DBBindableDouble.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbBindableDouble.h"
#include "sharedDatabaseInterface/DbServer.h"
#include <string>
// ======================================================================
using namespace DB;
BindableDouble::BindableDouble() : Bindable(), value(-999.0)
{
}
BindableDouble::BindableDouble(const double &_value) :
Bindable(sizeof(value)),
value(_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."));
}
}
}
double BindableDouble::getValue() const
{
return value;
}
void BindableDouble::setValue(const double &_value)
{
indicator=sizeof(value);
value=_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."));
}
}
}
BindableDouble &BindableDouble::operator=(const double &_value)
{
setValue(_value);
return *this;
}
void *BindableDouble::getBuffer()
{
return &value; //lint !e1536 // exposing private member (because DB interface will set it directly)
}
std::string BindableDouble::outputValue() const
{
char temp[255];
snprintf(temp,sizeof(temp),"%f",value);
temp[sizeof(temp)-1]='\0';
return std::string(temp);
}
// ======================================================================
@@ -0,0 +1,61 @@
// ======================================================================
//
// DBBindableDouble.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_DBBindableDouble_H
#define INCLUDED_DBBindableDouble_H
// ======================================================================
#include "sharedDatabaseInterface/DbBindableBase.h"
// ======================================================================
namespace DB {
/**
* Represents a double in C++, bound to a FLOAT(nn) or a NUMBER database column
* TODO: make variations of this for different precisions (when it is determined what precisions we need)
*/
class BindableDouble : public Bindable
{
double value;
public:
explicit BindableDouble(const double &_value);
BindableDouble();
double getValue() const;
void setValue(const double &_value);
BindableDouble &operator=(const double &_value);
void getValue(double &buffer) const;
void getValue(real &buffer) const;
void *getBuffer();
virtual std::string outputValue() const;
}; //lint !e1721 !e1509 // no virtual destructor, unusual operator =
}
// ----------------------------------------------------------------------
inline void DB::BindableDouble::getValue(double &buffer) const
{
buffer=getValue();
}
// ----------------------------------------------------------------------
inline void DB::BindableDouble::getValue(real &buffer) const
{
buffer=static_cast<real>(getValue());
}
// ======================================================================
#endif
@@ -0,0 +1,56 @@
// ======================================================================
//
// DBBindableInt64.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbBindableInt64.h"
#include <cstdio>
// ======================================================================
using namespace DB;
BindableInt64::BindableInt64()
{
}
// ----------------------------------------------------------------------
BindableInt64::BindableInt64(int64 value)
{
setValue(value);
}
// ----------------------------------------------------------------------
int64 BindableInt64::getValue() const
{
int64 temp;
char buffer[BindableInt64BufferSize+1];
BindableString<BindableInt64BufferSize>::getValue(buffer,BindableInt64BufferSize+1);
sscanf(buffer,INT64_FORMAT_SPECIFIER,&temp);
return temp;
}
// ----------------------------------------------------------------------
BindableInt64 &BindableInt64::operator=(int64 rhs)
{
setValue(rhs);
return *this;
}
// ----------------------------------------------------------------------
void BindableInt64::setValue(int64 rhs)
{
char buffer[BindableInt64BufferSize+1];
sprintf(buffer,INT64_FORMAT_SPECIFIER,rhs);
BindableString<BindableInt64BufferSize>::setValue(buffer);
}
// ======================================================================
@@ -0,0 +1,56 @@
// ======================================================================
//
// DBBindableInt64.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_DBBindableInt64_H
#define INCLUDED_DBBindableInt64_H
// ======================================================================
#include "sharedDatabaseInterface/DbBindableString.h"
// ======================================================================
#define BindableInt64BufferSize 21 // big enough to hold -(2^63)
namespace DB {
/**
* Represents an int64 in C++
*/
class BindableInt64 : public BindableString<BindableInt64BufferSize>
{
public:
BindableInt64();
explicit BindableInt64(int64 value);
int64 getValue() const;
void setValue(const int64 rhs);
BindableInt64 &operator=(const int64 rhs);
void getValue(int64 &buffer) const;
void getValue(uint64 &buffer) const;
};
}
// ----------------------------------------------------------------------
inline void DB::BindableInt64::getValue(int64 &buffer) const
{
buffer=getValue();
}
// ----------------------------------------------------------------------
inline void DB::BindableInt64::getValue(uint64 &buffer) const
{
buffer=static_cast<uint64>(getValue());
}
// ======================================================================
#endif
@@ -0,0 +1,64 @@
// ======================================================================
//
// DBBindableLong.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbBindableLong.h"
#include <string>
// ======================================================================
using namespace DB;
BindableLong::BindableLong() : Bindable(), value(-999)
{
}
BindableLong::BindableLong(long int _value) : Bindable(sizeof(value)), value(_value)
{
}
void *BindableLong::getBuffer()
{
return &value; //lint !e1536 // exposing private member
}
// ----------------------------------------------------------------------
long int BindableLong::getValue() const
{
return value;
}
// ----------------------------------------------------------------------
BindableLong &BindableLong::operator=(long int rhs)
{
indicator=sizeof(value);
value=rhs;
return *this;
}
// ----------------------------------------------------------------------
void BindableLong::setValue(long int rhs)
{
indicator=sizeof(value);
value=rhs;
}
// ----------------------------------------------------------------------
std::string BindableLong::outputValue() const
{
char temp[255];
snprintf(temp,sizeof(temp),"%li",value);
temp[sizeof(temp)-1]='\0';
return std::string(temp);
}
// ======================================================================
@@ -0,0 +1,95 @@
// ======================================================================
//
// DBBindableLong.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_DBBindableLong_H
#define INCLUDED_DBBindableLong_H
// ======================================================================
#include "sharedDatabaseInterface/DbBindableBase.h"
// ======================================================================
namespace DB {
/**
* Represents a long in C++, bound to an INTEGER or NUMBER database column
*/
class BindableLong : public Bindable
{
public:
BindableLong();
explicit BindableLong(long int _value);
long int getValue() const;
void setValue(const long int rhs);
BindableLong &operator=(const long int rhs);
// following alternate getValue's are provided for convenience, particularly in
// the auto-generated code:
void getValue(unsigned int &buffer) const;
void getValue(uint32 &buffer) const; // for some reason, our compiler is convinced that uint32 != unsigned int
void getValue(long int &buffer) const;
void getValue(int &buffer) const;
void getValue(int8 &buffer) const;
void getValue(uint8 &buffer) const;
void *getBuffer();
virtual std::string outputValue() const;
private:
long int value;
}; //lint !e1721 !e1509 // no virtual destructor, unusual operator =
}
// ----------------------------------------------------------------------
inline void DB::BindableLong::getValue(unsigned int &buffer) const
{
buffer=static_cast<unsigned int>(getValue());
}
// ----------------------------------------------------------------------
inline void DB::BindableLong::getValue(uint32 &buffer) const
{
buffer=static_cast<uint32>(getValue());
}
// ----------------------------------------------------------------------
inline void DB::BindableLong::getValue(long int &buffer) const
{
buffer=getValue();
}
// ----------------------------------------------------------------------
inline void DB::BindableLong::getValue(int &buffer) const
{
buffer=getValue();
}
// ----------------------------------------------------------------------
inline void DB::BindableLong::getValue(int8 &buffer) const
{
buffer=static_cast<int8>(getValue());
}
// ----------------------------------------------------------------------
inline void DB::BindableLong::getValue(uint8 &buffer) const
{
buffer=static_cast<uint8>(getValue());
}
// ======================================================================
#endif
@@ -0,0 +1,19 @@
// ======================================================================
//
// DBBindableString.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbBindableString.h"
// ======================================================================
std::string DB::BindableStringBase::outputValue() const
{
const std::string quote("\"");
return quote + std::string(m_buffer) + quote;
}
// ======================================================================
@@ -0,0 +1,326 @@
// ======================================================================
//
// DBBindableString.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_DBBindableString_H
#define INCLUDED_DBBindableString_H
// ======================================================================
#include "sharedDatabaseInterface/DbBindableBase.h"
#include "UnicodeUtils.h"
// ======================================================================
namespace DB
{
/**
* A large instrument resembling a cello.
*/
class BindableStringBase : public Bindable
{
public:
~BindableStringBase();
void *getBuffer();
int getS();
virtual std::string outputValue() const;
protected:
BindableStringBase(char *buffer, int s);
BindableStringBase(char *buffer, int s, const BindableStringBase &rhs);
void operator=(const BindableStringBase &rhs);
private:
BindableStringBase();
BindableStringBase(const BindableStringBase &rhs); // disable
private:
char *m_buffer;
int m_s;
};
inline BindableStringBase::BindableStringBase(char *buffer, int s) :
m_buffer(buffer),
m_s(s)
{
}
/**
* This takes the place of a copy contructor.
* It gets buffer and s from the derived class, instead of from rhs.
*/
inline BindableStringBase::BindableStringBase(char *buffer, int s, const BindableStringBase &rhs) :
Bindable(rhs),
m_buffer(buffer),
m_s(s)
{
DEBUG_FATAL(m_s!=rhs.m_s,("Cannot use BindableString copy constructor on different size strings.\n")); // compiler shouldn't allow this, but just to make sure...
}
inline BindableStringBase::~BindableStringBase()
{
m_buffer = 0;
}
inline void *BindableStringBase::getBuffer()
{
return m_buffer;
}
inline int BindableStringBase::getS()
{
return m_s;
}
inline void BindableStringBase::operator=(const BindableStringBase &rhs)
{
//does not copy m_buffer or m_s
DEBUG_FATAL(m_s!=rhs.m_s,("Cannot use BindableString::operator= on different size strings.\n")); // compiler shouldn't allow this, but just to make sure...
Bindable::operator=(rhs);
}
// ======================================================================
/** Template that allows creating a class representing a C++ char[] array
bound to a VARCHAR in the database.
BindableString is a template so that the size can be specified when it
is instantiated. The template parameter S represents the size of the
array.
Question: Why is this a template? Couldn't S be a parameter to the
constructor?
Short answer: Because of the way ODBC works, the size must be known at
compile time
Long answer: We want to be able to use these things in arrays that are
bound. The functions for binding an array do not allow an element of the
array to be a pointer to another location. Therefore, to work with ODBC,
the buffer for the string must be part of the class, not a pointer.
TODO: Currently this template represents 8-bit characters. Make it support
Unicode.
TODO: We have both setValue() functions and operator='s. Should just pick
one and use it.
*/
template<int S>
class BindableString : public BindableStringBase
{
public:
BindableString();
explicit BindableString(const Unicode::String &_value);
explicit BindableString(const std::string &_value);
BindableString(const BindableString<S> &rhs);
/** Copy the string to another string
*/
char *getValue(char *buffer, size_t bufsize) const;
/** Copy the string to a Unicode String class
*/
Unicode::String getValue() const;
/** Copy the string to an 8-bit String class
*/
std::string getValueASCII() const;
/** Allocate a new string and copy the buffer to it. The caller takes responsibility
for delete[]ing it later. (If the string is NULL, this returns a null pointer.)
*/
char *makeCopyOfValue() const;
/** Set the value of the bindable string from another (null-terminated) string
If the source buffer is too big, it FATAL's. Another alternative would be to have
it truncate the string. Right now, it's better to FATAL to avoid hard-to-find bugs
caused by the database fields being too small. However, might want to revist this
later.
*/
void setValue(const char *buffer);
/** Set the value of the bindable string from a String class. See also setValue(const char*).
*/
void setValue(const Unicode::String &buffer);
/**
* Set the value of the bindable string from a std::string.
*/
void setValue(const std::string &buffer);
/** Same as setValue
*/
BindableString &operator=(const Unicode::String &buffer);
BindableString &operator=(const std::string &buffer);
// Alternate forms of getValue, useful for auto-generated code (because of type conversion issues)
void getValue(Unicode::String &buffer) const;
void getValue(std::string &buffer) const;
int getS() const;
private:
char m_value[S+1]; // column of size S, plus one byte for a trailing null
};
// ======================================================================
// Template functions
template<int S>
BindableString<S>::BindableString()
: BindableStringBase(m_value, S)
{
}
template<int S>
BindableString<S>::BindableString(const Unicode::String &value)
: BindableStringBase(m_value, S)
{
setValue(value);
}
template<int S>
BindableString<S>::BindableString(const std::string &value)
: BindableStringBase(m_value, S)
{
setValue(value);
}
template<int S>
BindableString<S>::BindableString(const BindableString<S> &rhs)
: BindableStringBase(m_value, S, rhs)
{
strncpy(m_value,rhs.m_value,S+1);
}
template<int S>
char *BindableString<S>::getValue(char *buffer, size_t bufsize) const
{
if (isNull())
{
return strncpy(buffer,"\0",1); // in the database, a zero-length string and a NULL aren't really
// the same thing, but this is the closest we can do here.
}
return strncpy(buffer,m_value,(bufsize>(S+1))?(S+1):bufsize);
}
template<int S>
Unicode::String BindableString<S>::getValue() const
{
if (isNull())
{
return Unicode::String();
}
else
{
//-- Justin Randall [4/11/2001 5:56:56 PM] --
// @todo : value is currently a char, should be an short or Unicode::String::value_type or wchar_t
return Unicode::String(Unicode::narrowToWide(m_value));
}
}
template<int S>
std::string BindableString<S>::getValueASCII() const
{
if (isNull())
{
return std::string();
}
else
{
return std::string(m_value);
}
}
template<int S>
void BindableString<S>::setValue(const char *buffer)
{
if (buffer==0)
{
setNull();
return;
}
// the following is strncpy, but keeps a count of the number of characters
unsigned int i;
for (i=0;i<S+1;++i)
{
m_value[i]=buffer[i];
if (m_value[i]=='\0')
break;
}
FATAL((i==S+1) && (m_value[S]!='\0'),("Attempt to save string \"%s\" to the database. It is too long for the column.",buffer));
indicator=i; // set indicator to actual length of string
// m_value[S]='\0'; // guarantee null terminator -- uncomment if you remove the above FATAL
}
template<int S>
void BindableString<S>::setValue(const Unicode::String &buffer)
{
FATAL(buffer.size()>S,("Attempt to save a Unicode::String \"%s\"that is too long to the database.", Unicode::wideToNarrow(buffer).c_str()));
strncpy(m_value, Unicode::wideToNarrow(buffer).c_str(), S+1);
indicator=buffer.size();
}
template<int S>
void BindableString<S>::setValue(const std::string &buffer)
{
FATAL(strlen(buffer.c_str())>S,("Attempt to save a std::string \"%s\"that is too long to the database.", buffer.c_str()));
strncpy(m_value, buffer.c_str(), S+1);
indicator=strlen(buffer.c_str());
}
template<int S>
BindableString<S> &BindableString<S>::operator=(const Unicode::String &buffer)
{
setValue(buffer);
return *this;
}
template<int S>
BindableString<S> &BindableString<S>::operator=(const std::string &buffer)
{
setValue(buffer.c_str());
return *this;
}
template<int S>
char *BindableString<S>::makeCopyOfValue() const
{
if (isNull()) return 0;
char *target=new char[indicator+1];
strncpy(target,m_value,indicator+1);
return target;
}
template<int S>
void BindableString<S>::getValue(Unicode::String &buffer) const
{
buffer=getValue();
}
template<int S>
void BindableString<S>::getValue(std::string &buffer) const
{
buffer=getValueASCII();
}
template<int S>
int BindableString<S>::getS() const
{
return S;
}
// ======================================================================
}
#endif
@@ -0,0 +1,19 @@
// ======================================================================
//
// DBBindableUnicode.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbBindableUnicode.h"
// ======================================================================
std::string DB::BindableUnicodeBase::outputValue() const
{
const std::string quote("\"");
return quote + std::string(m_buffer) + quote;
}
// ======================================================================
@@ -0,0 +1,226 @@
// ======================================================================
//
// DBBindableUnicode.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_DBBindableUnicode_H
#define INCLUDED_DBBindableUnicode_H
// ======================================================================
#include "sharedDatabaseInterface/DbBindableBase.h"
#include "UnicodeUtils.h"
// ======================================================================
namespace DB
{
/**
* A large instrument resembling a cello.
*/
class BindableUnicodeBase : public Bindable
{
public:
~BindableUnicodeBase();
void *getBuffer();
int getS();
virtual std::string outputValue() const;
protected:
BindableUnicodeBase(char *buffer, int s);
BindableUnicodeBase(char *buffer, int s, const BindableUnicodeBase &rhs);
void operator=(const BindableUnicodeBase &rhs);
private:
BindableUnicodeBase();
BindableUnicodeBase(const BindableUnicodeBase &rhs); // disable
private:
char *m_buffer;
int m_s;
};
inline BindableUnicodeBase::BindableUnicodeBase(char *buffer, int s) :
m_buffer(buffer),
m_s(s)
{
}
/**
* This takes the place of a copy contructor.
* It gets buffer and s from the derived class, instead of from rhs.
*/
inline BindableUnicodeBase::BindableUnicodeBase(char *buffer, int s, const BindableUnicodeBase &rhs) :
Bindable(rhs),
m_buffer(buffer),
m_s(s)
{
DEBUG_FATAL(m_s!=rhs.m_s,("Cannot use BindableUnicode copy constructor on different size strings.\n")); // compiler shouldn't allow this, but just to make sure...
}
inline BindableUnicodeBase::~BindableUnicodeBase()
{
m_buffer = 0;
}
inline void *BindableUnicodeBase::getBuffer()
{
return m_buffer;
}
inline int BindableUnicodeBase::getS()
{
return m_s;
}
inline void BindableUnicodeBase::operator=(const BindableUnicodeBase &rhs)
{
//does not copy m_buffer or m_s
DEBUG_FATAL(m_s!=rhs.m_s,("Cannot use BindableUnicode::operator= on different size strings.\n")); // compiler shouldn't allow this, but just to make sure...
Bindable::operator=(rhs);
}
// ======================================================================
/** Template that allows creating a class representing a C++ char[] array
bound to a VARCHAR in the database.
BindableUnicode is a template so that the size can be specified when it
is instantiated. The template parameter S represents the size of the
array.
Question: Why is this a template? Couldn't S be a parameter to the
constructor?
Short answer: Because of the way ODBC works, the size must be known at
compile time
Long answer: We want to be able to use these things in arrays that are
bound. The functions for binding an array do not allow an element of the
array to be a pointer to another location. Therefore, to work with ODBC,
the buffer for the string must be part of the class, not a pointer.
TODO: Currently this template represents 8-bit characters. Make it support
Unicode.
TODO: We have both setValue() functions and operator='s. Should just pick
one and use it.
*/
template<int S>
class BindableUnicode : public BindableUnicodeBase
{
public:
BindableUnicode();
explicit BindableUnicode(const Unicode::String &_value);
BindableUnicode(const BindableUnicode<S> &rhs);
/** Copy the string to another string
*/
//char *getValue(char *buffer, size_t bufsize) const;
/** Copy the string to a Unicode String class
*/
Unicode::String getValue() const;
/** Set the value of the bindable string from a String class. See also setValue(const char*).
*/
void setValue(const Unicode::String &buffer);
/** Same as setValue
*/
BindableUnicode &operator=(const Unicode::String &buffer);
// Alternate forms of getValue, useful for auto-generated code (because of type conversion issues)
void getValue(Unicode::String &buffer) const;
int getS() const;
private:
char m_value[S+1]; // column of size S, plus one byte for a trailing null
};
// ======================================================================
// Template functions
template<int S>
BindableUnicode<S>::BindableUnicode()
: BindableUnicodeBase(m_value, S)
{
}
template<int S>
BindableUnicode<S>::BindableUnicode(const Unicode::String &value)
: BindableUnicodeBase(m_value, S)
{
setValue(value);
}
template<int S>
BindableUnicode<S>::BindableUnicode(const BindableUnicode<S> &rhs)
: BindableUnicodeBase(m_value, S, rhs)
{
strncpy(m_value,rhs.m_value,S+1);
}
template<int S>
Unicode::String BindableUnicode<S>::getValue() const
{
if (isNull())
{
return Unicode::String();
}
else
{
Unicode::String str;
std::basic_string<char> cstr (m_value, m_value + indicator);
str = Unicode::utf8ToWide(cstr);
return str;
//-- Justin Randall [4/11/2001 5:56:56 PM] --
// @todo : value is currently a char, should be an short or Unicode::String::value_type or wchar_t
//return Unicode::String(Unicode::narrowToWide(m_value));
}
}
template<int S>
void BindableUnicode<S>::setValue(const Unicode::String &buffer)
{
FATAL(buffer.size()>S,("Attempt to save a Unicode::String \"%s\"that is too long to the database.", Unicode::wideToNarrow(buffer).c_str()));
std::string str;
str = Unicode::wideToUTF8(buffer, str);
indicator = (str.size()>S ? S : str.size());
memcpy(m_value, str.c_str(),indicator);
m_value[indicator] = '\0';
}
template<int S>
BindableUnicode<S> &BindableUnicode<S>::operator=(const Unicode::String &buffer)
{
setValue(buffer);
return *this;
}
template<int S>
void BindableUnicode<S>::getValue(Unicode::String &buffer) const
{
buffer.assign(getValue());
}
template<int S>
int BindableUnicode<S>::getS() const
{
return S;
}
// ======================================================================
}
#endif
@@ -0,0 +1,13 @@
// ======================================================================
//
// DBBufferRow.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbBufferRow.h"
// ======================================================================
// ======================================================================
@@ -0,0 +1,53 @@
// ======================================================================
//
// DBBufferRow.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
//TODO: Is this file obsolete?
#ifndef INCLUDED_DBBufferRow_H
#define INCLUDED_DBBufferRow_H
// ======================================================================
#include "sharedDatabaseInterface/DbRow.h"
// ======================================================================
namespace DB
{
/**
* A BufferRow is a Row that works with the TableBuffer class.
*
* A BufferRow is a Row that represents a Row from a table (not a view
* or a query that joins multiple tables). It implements various
* virtual functions that the TableBuffer class uses.
*/
struct BufferRow:public Row
{
/**
* Combines the values in this row with the values in newRow.
*
* For each column:
* If the column is null in newRow, do nothing. (Leave the value
* in this row unchanged.)
* If the column is not null in newRow, replace the value in this
* row with the value in newRow.
*/
virtual void combine(const DB::Row &newRow) =0;
/**
* Makes a new copy of this row.
*/
virtual BufferRow *copy(void) const =0;
};
} // namespace
// ======================================================================
#endif
@@ -0,0 +1,33 @@
// ======================================================================
//
// DbException.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbException.h"
// ======================================================================
using namespace DB;
// ======================================================================
Exception::Exception(int errorNumber, const std::string &errorDescription, const std::string &contextDescription) :
m_errorNumber(errorNumber),
m_errorDescription(errorDescription),
m_contextDescription(contextDescription)
{
}
// ----------------------------------------------------------------------
Exception::Exception(int errorNumber, const std::string &errorDescription) :
m_errorNumber(errorNumber),
m_errorDescription(errorDescription),
m_contextDescription()
{
}
// ======================================================================
@@ -0,0 +1,62 @@
// ======================================================================
//
// DbException.h
// copyright (c) 2003 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_DbException_H
#define INCLUDED_DbException_H
// ======================================================================
#include <string>
// ======================================================================
namespace DB
{
class Exception
{
public:
Exception(int errorNumber, const std::string &errorDescription, const std::string &contextDescription);
Exception(int errorNumber, const std::string &errorDescription);
public:
int getErrorNumber() const;
const std::string & getErrorDescription() const;
const std::string & getContextDescription() const;
private:
int m_errorNumber;
std::string m_errorDescription;
std::string m_contextDescription;
};
// ======================================================================
inline int Exception::getErrorNumber() const
{
return m_errorNumber;
}
// ----------------------------------------------------------------------
inline const std::string & Exception::getErrorDescription() const
{
return m_errorDescription;
}
// ----------------------------------------------------------------------
inline const std::string & Exception::getContextDescription() const
{
return m_contextDescription;
}
// ======================================================================
} // namespace
// ======================================================================
#endif
@@ -0,0 +1,19 @@
// ======================================================================
//
// DBModeQuery.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbModeQuery.h"
// ======================================================================
DB::ModeQuery::~ModeQuery()
{
delete data;
}
// ======================================================================
@@ -0,0 +1,120 @@
/* DBModeQuery.h
*
* Query objects that support different modes of operation
*
*/
#ifndef _DBMODEQUERY_H
#define _DBMODEQUERY_H
//-----------------------------------------------------------------------
#include "sharedDatabaseInterface/DbQuery.h"
#include "sharedDatabaseInterface/DbRow.h"
//-----------------------------------------------------------------------
namespace DB
{
/**
* A ModeQuery is a Query that can be in update, insert, select, or delete mode.
*
* This class is designed to work with the TableBuffer class.
*
* Derive from this class to make a query for a specific purpose.
* Implement the following in the derived class:
* 1) A constructor that initializes _data_ to point to a row of the appropriate type.
* 2) A bind function (will need to dynamic_cast _data_ to the appropriate type of row)
* 3) A getSQL() function
*
* Note that the copy() function must be defined for the type of row used.
*
* Note also that getSQL() will need to return different values depending on the mode. Bind()
* may also need to behave differently in different modes, depending on the query. The default
* destructor deletes _data_, so it is not necessary to do so in a derived destructor.
*/
class ModeQuery : public Query
{
public:
enum Mode {mode_UPDATE,mode_INSERT,mode_DELETE,mode_SELECT,mode_INVALID};
Mode mode; //TODO: rename to m_mode
protected:
Row *data;
public:
explicit ModeQuery(Row *derivedRow);
virtual ~ModeQuery();
void setData(const Row &_data);
const Row &getData(void) const;
void updateMode();
void insertMode();
void deleteMode();
void selectMode();
private:
ModeQuery(); //disable
ModeQuery(const ModeQuery &); //disable
ModeQuery & operator=(const ModeQuery &); //disable
};
//-----------------------------------------------------------------------
// Inline functions
inline ModeQuery::ModeQuery(Row *derivedRow) :
Query(),
mode (mode_INVALID),
data(derivedRow)
{
}
//------------------------------------------------------------------------
inline void ModeQuery::insertMode()
{
mode=mode_INSERT;
}
//------------------------------------------------------------------------
inline void ModeQuery::updateMode()
{
mode=mode_UPDATE;
}
//------------------------------------------------------------------------
inline void ModeQuery::deleteMode()
{
mode=mode_DELETE;
}
//------------------------------------------------------------------------
inline void ModeQuery::selectMode()
{
mode=mode_SELECT;
}
//------------------------------------------------------------------------
inline const Row &ModeQuery::getData() const
{
return *data;
}
// ----------------------------------------------------------------------
inline void ModeQuery::setData(const Row &_data)
{
data->copy(_data);
}
// ----------------------------------------------------------------------
} // namespace
#endif
@@ -0,0 +1,70 @@
// ======================================================================
//
// DbProfiler.cpp
// copyright (c) 2003 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbProfiler.h"
#include <map>
#include <string>
#include "sharedLog/Log.h"
// ======================================================================
namespace DB
{
Profiler::Profiler() :
m_queryDataMap(new QueryDataMapType)
{
}
// ----------------------------------------------------------------------
Profiler::~Profiler()
{
delete m_queryDataMap;
m_queryDataMap = 0;
}
// ----------------------------------------------------------------------
void Profiler::addQueryProfileData(const std::string &queryName, int execTime, int fetchTime, int execCount, int fetchCount)
{
QueryData &data = (*m_queryDataMap)[queryName];
data.m_execTime += execTime;
data.m_fetchTime += fetchTime;
data.m_execCount += execCount;
data.m_fetchCount += fetchCount;
}
// ----------------------------------------------------------------------
void Profiler::debugOutput()
{
// DEBUG_REPORT_LOG(true,("Query profile:\n"));
for (QueryDataMapType::const_iterator i=m_queryDataMap->begin(); i!=m_queryDataMap->end(); ++i)
{
LOG("QueryProfile",("\t%s\t%i ms/exec (%i execs in %i ms, %i fetches in %i ms)\n",
i->first.c_str(), (i->second.m_execTime / i->second.m_execCount), i->second.m_execCount,
i->second.m_execTime, i->second.m_fetchCount, i->second.m_fetchTime));
}
// DEBUG_REPORT_LOG(true,("End query profile\n"));
}
// ----------------------------------------------------------------------
Profiler::QueryData::QueryData() :
m_execTime(0),
m_fetchTime(0),
m_execCount(0),
m_fetchCount(0)
{
}
} // namespace
// ======================================================================
@@ -0,0 +1,43 @@
// ======================================================================
//
// DbProfiler.h
// copyright (c) 2003 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_DbProfiler_H
#define INCLUDED_DbProfiler_H
// ======================================================================
namespace DB
{
class Profiler
{
public:
Profiler();
~Profiler();
void addQueryProfileData(const std::string &queryName, int execTime, int fetchTime, int execCount, int fetchCount);
void debugOutput();
private:
class QueryData
{
public:
QueryData();
public:
int m_execTime;
int m_fetchTime;
int m_execCount;
int m_fetchCount;
};
typedef stdmap<std::string, QueryData>::fwd QueryDataMapType;
QueryDataMapType *m_queryDataMap;
};
} //namespace
// ======================================================================
#endif
@@ -0,0 +1,25 @@
// ======================================================================
//
// DBProtocol.def
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_DBProtocol_DEF
#define INCLUDED_DBProtocol_DEF
// ======================================================================
namespace DB
{
const int PROTOCOL_DEFAULT=0;
const int PROTOCOL_ODBC=1;
const int PROTOCOL_OCI=2;
typedef int Protocol;
}
// ======================================================================
#endif
@@ -0,0 +1,334 @@
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbQuery.h"
#include "sharedDatabaseInterface/DbException.h"
#include "sharedDatabaseInterface/DbQueryImplementation.h"
#include "sharedDatabaseInterface/DbServer.h"
#include "sharedDatabaseInterface/DbSession.h"
#include "sharedFoundation/Clock.h"
#include "sharedLog/Log.h"
#include <string>
using namespace DB;
namespace DBQueryNamespace
{
void logLargeText(std::string const & logSection, std::string const & text);
}
Query::Query() :
impl(0),
m_session(0),
inUse(false),
m_execTime(0),
m_fetchTime(0),
m_execCount(0),
m_fetchCount(0),
m_rowsFetched(0),
m_debugName(0),
m_queryMode(MODE_SQL)
{
}
Query::~Query()
{
if (inUse)
done();
delete impl;
delete m_debugName;
impl = 0;
m_debugName = 0;
} //lint !e1740 // dtor doesn't delete m_session (because we don't own it)
int Query::fetch()
{
int startTime = 0;
if (Server::isProfilingEnabled())
startTime = Clock::timeMs();
NOT_NULL(impl);
m_rowsFetched = impl->fetch();
if (Server::isProfilingEnabled())
{
m_fetchTime += Clock::timeMs() - startTime;
}
if (m_rowsFetched >= 0)
{
m_fetchCount += m_rowsFetched;
return m_rowsFetched;
}
else
return -1;
}
void Query::done()
{
if (inUse) // so that it's safe to call Done() on a query that hasn't been used
{
NOT_NULL(impl);
NOT_NULL(m_session);
impl->done();
m_session->queryDone();
m_session->addQueryCount(m_execCount, m_fetchCount);
if (Server::isProfilingEnabled())
{
NOT_NULL(m_debugName); // should have been set by setup()
Server::addQueryProfileData(*m_debugName, m_execTime, m_fetchTime, m_execCount, m_fetchCount);
// reset the profiler data in case we run this query again:
m_execTime=0;
m_fetchTime=0;
m_execCount=0;
m_fetchCount=0;
}
inUse=false;
m_session=0;
}
}
// ----------------------------------------------------------------------
/**
* Returns the number of rows affected by the most recent query. (Only applies
* to DML queries.)
*/
int Query::rowCount()
{
if (!inUse)
{
return 0;
}
else
{
NOT_NULL(impl);
return impl->rowCount();
}
}
// ----------------------------------------------------------------------
bool Query::setup(Session *session)
{
if (impl == 0)
{
impl=session->createQueryImpl(this);
}
NOT_NULL(impl);
NOT_NULL(session);
m_session=session;
if (Server::isProfilingEnabled() && !m_debugName)
{
m_debugName = new std::string;
getDebugName(*m_debugName);
}
if (impl->setup(session))
{
inUse=true;
return true;
}
else
return false;
}
bool Query::prepare()
{
NOT_NULL(impl);
return impl->prepare();
}
bool Query::exec()
{
int startTime = 0;
if (Server::isProfilingEnabled())
startTime = Clock::timeMs();
m_queryMode=getExecutionMode();
NOT_NULL(impl);
if (Server::isVerboseModeEnabled())
{
std::string context;
getDebugName(context);
DEBUG_REPORT_LOG(true,("query: %s\n",context.c_str()));
}
bool result = impl->exec();
if (Server::isProfilingEnabled())
{
m_execTime += Clock::timeMs() - startTime;
}
++m_execCount;
if (! result)
{
std::string data = outputDataValues();
LOG("DatabaseError",("Data from previous error:"));
DBQueryNamespace::logLargeText("DatabaseError", data);
done();
}
return result;
}
void Query::setColArrayMode(size_t skipSize, size_t numElements)
{
NOT_NULL(impl);
impl->setColArrayMode(skipSize, numElements);
}
bool Query::bindCol(BindableLong &buffer)
{
NOT_NULL(impl);
return impl->bindCol(buffer);
}
bool Query::bindParameter(BindableLong &buffer)
{
NOT_NULL(impl);
return impl->bindParameter(buffer);
}
bool Query::bindCol(BindableDouble &buffer)
{
NOT_NULL(impl);
return impl->bindCol(buffer);
}
bool Query::bindParameter(BindableDouble &buffer)
{
NOT_NULL(impl);
return impl->bindParameter(buffer);
}
bool Query::bindCol(BindableStringBase &buffer)
{
NOT_NULL(impl);
return impl->bindCol(buffer);
}
bool Query::bindParameter(BindableStringBase &buffer)
{
NOT_NULL(impl);
return impl->bindParameter(buffer);
}
bool Query::bindCol(BindableUnicodeBase &buffer)
{
NOT_NULL(impl);
return impl->bindCol(buffer);
}
bool Query::bindParameter(BindableUnicodeBase &buffer)
{
NOT_NULL(impl);
return impl->bindParameter(buffer);
}
bool Query::bindCol(BindableBool &buffer)
{
NOT_NULL(impl);
return impl->bindCol(buffer);
}
bool Query::bindParameter(BindableBool &buffer)
{
NOT_NULL(impl);
return impl->bindParameter(buffer);
}
bool Query::bindParameter(BindableVarray &buffer)
{
NOT_NULL(impl);
return impl->bindParameter(buffer);
}
// ----------------------------------------------------------------------
/**
* Get the protocol being used to communicate with the database.
*
* @returns The protocol being used, or PROTOCOL_DEFAULT if the query is not
* associated with a database connection.
*/
Protocol Query::getProtocol() const
{
if (inUse)
{
NOT_NULL(impl);
return impl->getProtocol();
}
else
return PROTOCOL_DEFAULT;
}
// ----------------------------------------------------------------------
/**
* Override this function to change the execution mode for the query.
*
* This function gets invoked after the QueryImpl has been created, so
* it can return different values depending on the protocol used.
*
* The default implementation returns MODE_SQL, which is suitable for
* most purposes.
*/
Query::QueryMode Query::getExecutionMode() const
{
return MODE_SQL;
}
// ----------------------------------------------------------------------
/** Override this function to return the debugging name for the query.
* The non-overriden version calls getSQL() and uses the result as the query name.
* Not const because getSQL() isn't const.
*/
void Query::getDebugName(std::string &debugName)
{
getSQL(debugName);
}
// ----------------------------------------------------------------------
std::string Query::outputDataValues() const
{
return impl->outputDataValues();
}
// ----------------------------------------------------------------------
void DBQueryNamespace::logLargeText(std::string const & logSection, std::string const & text)
{
int const targetLineSize = 80;
int const maxLineSize = 100;
char buffer[maxLineSize+1];
buffer[sizeof(buffer)-1]='\0';
int linePos = 0;
for (std::string::const_iterator sourcePos = text.begin(); sourcePos != text.end(); ++sourcePos)
{
if (*sourcePos < 27)
buffer[linePos++]='*'; // Hide unprintable/garbage/control characters
else
buffer[linePos++]=*sourcePos;
if ((linePos >= targetLineSize && *sourcePos == ' ') || (linePos >= maxLineSize))
{
buffer[linePos]='\0';
LOG(logSection.c_str(),(buffer));
linePos=0;
}
}
if (linePos != 0)
{
buffer[linePos]='\0';
LOG(logSection.c_str(),(buffer));
}
}
// ======================================================================
@@ -0,0 +1,157 @@
/* DBQuery.h
*
* Definition of the base query class. Override this class to make
* queries for specific purposes.
*
* ODBC version
*/
#ifndef _DBQUERY_H
#define _DBQUERY_H
//#include "sharedDatabaseInterface/SQLC_Defs.h"
#include "sharedDatabaseInterface/DbQueryImplementation.h" //TODO: Do we want to include this?
#include "sharedDatabaseInterface/DbProtocol.def"
namespace DB {
class Session;
class QueryImpl;
class BindableLong;
class BindableVarray;
class Query
{
public:
enum QueryMode {MODE_SQL, MODE_DML, MODE_PROCEXEC, MODE_PLSQL_REFCURSOR};
private:
QueryImpl *impl;
Session *m_session;
bool inUse;
int m_execTime;
int m_fetchTime;
int m_execCount;
int m_fetchCount;
int m_rowsFetched;
std::string *m_debugName;
/**
* Flag for the type of statement the query will run.
*
* Depending on the mode of operation, the query may need to be executed differently.
* In particular, some types of queries do not need to call bindColumns(), or may need to
* call it at different times.
*
* MODE_SQL is a query that may return rows. (The system allows DML statements to be sent using MODE_SQL, provided
* they bind no columns and never invoke fetch().)
* MODE_DML is a statement that updates rows. It will not return rows.
* MODE_PROCEXEC is a statement that invokes a stored procedure. It will not return rows, but it may alter
* parameters bound with bindParameter().
* MODE_PLSQL_REFCURSOR is Oracle-specific.
*/
QueryMode m_queryMode;
bool m_useProcFetch;
/** Because database results are bound to the memory location of members
of Query, copying them is not allowed. Do not define this function.
*/
Query(const Query &rhs);
/** Because database results are bound to the memory location of members
of Query, copying them is not allowed. Do not define this function.
*/
Query &operator=(const Query &rhs);
protected:
/** Switches to array mode to return an array of results, rather than a single row.
* Call this first, then call the bindCol functions with the first element in the array.
*/
void setColArrayMode(size_t skipSize, size_t numElements);
bool bindCol(BindableLong &buffer);
bool bindParameter(BindableLong &buffer);
bool bindCol(BindableDouble &buffer);
bool bindParameter(BindableDouble &buffer);
bool bindCol(BindableStringBase &buffer);
bool bindParameter(BindableStringBase &buffer);
bool bindCol(BindableUnicodeBase &buffer);
bool bindParameter(BindableUnicodeBase &buffer);
bool bindCol(BindableBool &buffer);
bool bindParameter(BindableBool &buffer);
bool bindParameter(BindableVarray &buffer);
Protocol getProtocol() const;
public:
// functions to use as-is:
Query();
virtual ~Query();
int fetch();
int getNumRowsFetched() const;
void done();
int rowCount();
QueryMode getMode() const;
void setMode(QueryMode newMode);
std::string outputDataValues() const;
// functions to override:
/** Override this function to return the SQL command for the query.
*/
virtual void getSQL(std::string &sql)=0;
/** Override this function to bind the results returned by the query to
variables or to bind parameters in the query.
See the Database Library documentation for more information, or refer to
the various Bindable types. An implementation of bind will probably
include lines like
<pre>
mydata.BindCol(1,this);
myparameter.BindParameter(1,this);
</pre>
*/
virtual bool bindParameters()=0;
virtual bool bindColumns()=0;
virtual QueryMode getExecutionMode() const;
virtual void getDebugName(std::string &debugName);
bool setup(Session *session);
bool prepare();
bool exec();
};
// ----------------------------------------------------------------------
inline Query::QueryMode Query::getMode() const
{
return m_queryMode;
}
// ----------------------------------------------------------------------
inline void Query::setMode(Query::QueryMode newMode)
{
m_queryMode=newMode;
}
// ----------------------------------------------------------------------
inline int Query::getNumRowsFetched() const
{
return m_rowsFetched;
}
// ----------------------------------------------------------------------
} //namespace
// ======================================================================
#endif
@@ -0,0 +1,89 @@
// ======================================================================
//
// DBQueryImpl.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_DBQueryImpl_H
#define INCLUDED_DBQueryImpl_H
// ======================================================================
#include "sharedDatabaseInterface/DbProtocol.def"
// ======================================================================
namespace DB
{
class BindableBool;
class BindableDouble;
class BindableInt64;
class BindableLong;
class BindableStringBase;
class BindableUnicodeBase;
class BindableVarray;
class Query;
class Session;
/**
* A class to contain the database-specific implementation of a
* query.
*
* The constructor of Query creates an instance of QueryImpl. This
* allows the library user to derive classes from Query without
* knowing specifics of the implementation.
*/
class QueryImpl
{
protected:
Query *m_query;
public:
explicit QueryImpl(Query *query);
virtual ~QueryImpl() {}; //lint !e1540 //We don't delete m_query (because we don't own it)
virtual bool setup(Session *session) =0;
virtual bool prepare() =0;
virtual int fetch() =0;
virtual void done() =0;
virtual int rowCount() =0; //TODO: Should be getRowCount() to be more consistent
virtual bool exec() =0;
virtual Protocol getProtocol() const =0;
virtual void setColArrayMode(size_t skipSize, size_t numElements)=0;
virtual bool bindCol(BindableLong &buffer) =0;
virtual bool bindParameter(BindableLong &buffer) =0;
virtual bool bindCol(BindableDouble &buffer) =0;
virtual bool bindParameter(BindableDouble &buffer) =0;
virtual bool bindCol(BindableStringBase &buffer) =0;
virtual bool bindParameter(BindableStringBase &buffer) =0;
virtual bool bindCol(BindableUnicodeBase &buffer) =0;
virtual bool bindParameter(BindableUnicodeBase &buffer) =0;
virtual bool bindCol(BindableBool &buffer) =0;
virtual bool bindParameter(BindableBool &buffer) =0;
virtual bool bindParameter(BindableVarray &buffer) =0;
virtual std::string outputDataValues() const =0;
private:
QueryImpl(); // disable
QueryImpl(const QueryImpl &); // disable
QueryImpl & operator=(const QueryImpl &); // disable
};
}
// ======================================================================
inline DB::QueryImpl::QueryImpl(DB::Query *query) :
m_query(query)
{
}
// ======================================================================
#endif
@@ -0,0 +1,43 @@
// ======================================================================
//
// DBRow.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbRow.h"
volatile int DB::Row::m_sRowsCreated = 0;
volatile int DB::Row::m_sRowsDeleted = 0;
// ----------------------------------------------------------------------
DB::Row::Row()
{
++m_sRowsCreated;
}
// ----------------------------------------------------------------------
DB::Row::Row( const Row& )
{
++m_sRowsCreated;
}
// ----------------------------------------------------------------------
DB::Row::~Row()
{
++m_sRowsDeleted;
}
// ----------------------------------------------------------------------
void DB::Row::copy(const Row &rhs)
{
UNREF(rhs);
FATAL(true,("Row::copy() invoked. This error probably means that copy() was not implemented for a class derived from Row."));
}
// ======================================================================
@@ -0,0 +1,58 @@
// ======================================================================
//
// DBRow.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_DBRow_H
#define INCLUDED_DBRow_H
// ======================================================================
namespace DB
{
/**
* This is the base class for classes that represent a row of data returned
* from the database.
*
* The goal is that in many cases, classes derived from Row will be generated
* directly from the database schema. Therefore, the class is kept as simple
* as possible.
*/
struct Row
{
Row();
Row( const Row& );
virtual ~Row();
/**
* This function is like a virtual operator=.
*
* Implement this function in derived classes. It should do something
* equivalent to *this = dynamic_cast<const derived_class_name&>(rhs)
*
* This function is not pure virtual so that derived classes do not need
* to define it if they do not plan to use it. However, the default
* implementation will FATAL.
*
* @todo We could make a CopyableRow class derived from Row that has
* this function as pure virtual. However, that might limit our ability
* to generate Row's directly from the database schema without regards to
* how they will be used.
*/
virtual void copy(const Row &rhs);
static int getRowsCreated() { return m_sRowsCreated; }
static int getRowsDeleted() { return m_sRowsDeleted; }
private:
static volatile int m_sRowsCreated;
static volatile int m_sRowsDeleted;
};
} // namespace
// ======================================================================
#endif
@@ -0,0 +1,410 @@
// ======================================================================
//
// DBServer.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbServer.h"
#include <string>
#include "sharedDatabaseInterface/DbSession.h"
#include "sharedDatabaseInterface/DbProfiler.h"
#include "sharedFoundation/ExitChain.h"
#include "sharedFoundation/Os.h"
#include "sharedLog/Log.h"
#ifdef DBLIBRARY_ODBC
#include "OdbcServer.h" //TODO: is this the best way to do DBServer::create()
#endif
#ifdef DBLIBRARY_OCI
#include "OciServer.h"
#endif
using namespace DB;
// ======================================================================
Mutex Server::ms_profileMutex;
bool Server::ms_enableProfiling = false;
bool Server::ms_enableVerboseMode = false;
DB::Profiler *Server::ms_profiler = NULL;
int Server::ms_reconnectTime=0;
int Server::ms_maxErrorCountBeforeDisconnect=5;
int Server::ms_maxErrorCountBeforeBailout=10;
int Server::ms_errorSleepTime=5000;
int Server::ms_disconnectSleepTime=45000;
int Server::ms_execCount=0;
int Server::ms_fetchCount=0;
int Server::ms_prefetchNumRows=0;
int Server::ms_prefetchMemory=0;
bool Server::ms_fatalOnError=false;
bool Server::ms_fatalOnDataError=false;
// ======================================================================
Server::SesListElem::SesListElem (Session *_ses, SesListElem *_next) : ses (_ses), next (_next)
{
}
// ----------------------------------------------------------------------
Server::Server(const char *_dsn, const char *_uid, const char *_pwd, bool useMemoryManager) :
sessionList (NULL),
sessionListLock(),
m_useMemoryManager(useMemoryManager)
{
strncpy(dsn,_dsn,sizeof(dsn)-1);
strncpy(uid,_uid,sizeof(uid)-1);
strncpy(pwd,_pwd,sizeof(pwd)-1);
//insure terminating \0:
dsn[sizeof(dsn)-1]='\0';
uid[sizeof(uid)-1]='\0';
pwd[sizeof(pwd)-1]='\0';
}
// ----------------------------------------------------------------------
// Server destructor
// TODO: what to do if deallocating handles failes? (This could happen if connection isn't closed properly, etc.)
Server::~Server()
{
}
// ----------------------------------------------------------------------
/**
* Establish connections to the database server.
* Sessions will be pre-connected and put in the pool of sessions. The
* caller can later request up to that number of sessions by calling
* GetSession(), with no blocking. Requests for additional sessions may
* block.
*
* @param numSessions The number of sessions to establish.
*/
bool Server::connect(int numSessions)
{
disconnect();
for (int i=0;i<numSessions;i++)
{
Session *ses=createSession();
if (!ses->connect())
{
ses->disconnect();
LOG("DatabaseError", ("Failed to connect to database in getSession()"));
FATAL(true, ("Failed to connect to database in getSession()"));
}
pushSession (ses);
}
return true;
}
// ----------------------------------------------------------------------
/**
* Drop all the sessions in the pool of sessions.
* After calling Disconnect(), any call to GetSession() will require
* establishing a new connection to the database server.
* Note that this call only affects Sessions in the pool. Sessions that
* are currently in use are not affected.
*/
bool Server::disconnect()
{
Session *ses=popSession();
while(ses)
{
delete ses;
ses=popSession();
}
return true;
}
// ----------------------------------------------------------------------
/**
* Get a Session object, representing a session on the database server.
* Will return a Session object from the pool, if one is avaiable.
* Otherwise, it will establish a new session. Warning: establishing
* a new session may require a database roundtrip. (i.e. It may block.)
* To avoid blocking, use connect() ahead of time to establish all the
* needed Sessions.
*/
Session *Server::getSession()
{
Session *ses=popSession();
if (!ses) // pool was empty, so make a new one. TODO: set a limit on max # of sessions
{
ses=createSession();
while (!ses->connect())
{
ses->disconnect();
LOG("DatabaseError", ("Failed to connect to database in getSession(). Will reconnect in 30 seconds."));
Os::sleep(30000);
}
}
return ses;
}
// ----------------------------------------------------------------------
/**
* Call when finished with a Session object.
* Returns the Session object to the pool.
* @todo for debugging, make sure the session released actually came from this server
*/
void Server::releaseSession(Session *session)
{
session->reset();
pushSession(session);
}
// ----------------------------------------------------------------------
void Server::pushSession(Session *session)
{
sessionListLock.enter();
SesListElem *e=new SesListElem(session, sessionList);
sessionList=e;
sessionListLock.leave();
}
// ----------------------------------------------------------------------
Session *Server::popSession()
{
sessionListLock.enter();
SesListElem *e=sessionList;
if (e)
{
Session *ses=e->ses;
sessionList=e->next;
delete e;
sessionListLock.leave();
return ses;
}
else
{
sessionListLock.leave();
return NULL;
}
}
// ----------------------------------------------------------------------
Server *Server::create(const char *_dsn, const char *_uid, const char *_pwd, Protocol protocol, bool useMemoryManager)
{
UNREF(_dsn);
UNREF(_uid);
UNREF(_pwd);
switch (protocol)
{
#ifdef DBLIBRARY_ODBC
case PROTOCOL_ODBC:
return new ODBCServer(_dsn,_uid,_pwd);
#endif
#ifdef DBLIBRARY_OCI
case PROTOCOL_OCI:
return new OCIServer(_dsn,_uid,_pwd, useMemoryManager);
#endif
case PROTOCOL_DEFAULT:
// Create any kind of server we can, prefering ODBCServer
#ifdef DBLIBRARY_ODBC
return new ODBCServer(_dsn,_uid,_pwd);
#endif
#ifdef DBLIBRARY_OCI
return new OCIServer(_dsn,_uid,_pwd, useMemoryManager);
#endif
default:
FATAL(true,("Database protocol specified in Server::create() is not available in this build of the library.\n"));
return 0;
}
}
// ----------------------------------------------------------------------
Protocol Server::getProtocolByName(const std::string &name)
{
#ifdef DBLIBRARY_ODBC
if (name=="ODBC")
return PROTOCOL_ODBC;
#endif
#ifdef DBLIBRARY_OCI
if (name=="OCI")
return PROTOCOL_OCI;
#endif
if (name=="DEFAULT")
return PROTOCOL_DEFAULT;
FATAL(true,("Specified protocol (%s) is not available in this version of the database library.",name.c_str()));
return PROTOCOL_DEFAULT;
}
// ----------------------------------------------------------------------
void Server::addQueryProfileData(const std::string &queryName, int execTime, int fetchTime, int execCount, int fetchCount)
{
ms_profileMutex.enter();
DEBUG_FATAL(!isProfilingEnabled(),("Programmer bug: you're supposed to check whether profiling is enabled before calling DB::Server::addProfileData (or there could be a race condition that is disabling profiling while queries are running).\n"));
if (!ms_profiler)
{
ms_profiler = new DB::Profiler;
}
ms_profiler->addQueryProfileData(queryName,execTime,fetchTime,execCount,fetchCount);
ms_profileMutex.leave();
}
// ----------------------------------------------------------------------
void Server::debugOutputProfile()
{
ms_profileMutex.enter();
if (ms_profiler)
ms_profiler->debugOutput();
else
DEBUG_REPORT_LOG(true,("No database profiler.\n"));
ms_profileMutex.leave();
}
// ----------------------------------------------------------------------
/**
* Stop collecting profile data and delete the Profiler.
*/
void Server::endProfiling()
{
ms_profileMutex.enter();
delete ms_profiler;
ms_profiler = NULL;
ms_enableProfiling = false;
ms_profileMutex.leave();
}
// ----------------------------------------------------------------------
/**
* Set a timeout for server connections. If a connection to the database
* has been open for more than reconnectTime, it will drop the connection
* and reestablish it the next time Session::reset() is called.
*/
void Server::setReconnectTime(int reconnectTime)
{
ms_reconnectTime = reconnectTime;
}
// ----------------------------------------------------------------------
/**
* Count the total number of queries executed and the total number of fetches
* for profiling. (This level of profiling is always enabled. The
* per-query profiling is optionally enabled.)
*/
void Server::addQueryCount(int execCount, int fetchCount)
{
ms_profileMutex.enter();
ms_execCount+=execCount;
ms_fetchCount+=fetchCount;
ms_profileMutex.leave();
}
// ----------------------------------------------------------------------
void Server::enablePrefetch(int numRows, int memory)
{
ms_prefetchNumRows = numRows;
ms_prefetchMemory = memory;
}
// ----------------------------------------------------------------------
void Server::disablePrefetch()
{
ms_prefetchNumRows = 0;
}
// ----------------------------------------------------------------------
bool Server::isPrefetchEnabled()
{
return (ms_prefetchNumRows > 0);
}
// ----------------------------------------------------------------------
int Server::getPrefetchRows()
{
return ms_prefetchNumRows;
}
// ----------------------------------------------------------------------
int Server::getPrefetchMemory()
{
return ms_prefetchMemory;
}
// ----------------------------------------------------------------------
void Server::getAndResetQueryCount(int &execCount, int &fetchCount)
{
ms_profileMutex.enter();
execCount=ms_execCount;
fetchCount=ms_fetchCount;
ms_execCount=0;
ms_fetchCount=0;
ms_profileMutex.leave();
}
// ----------------------------------------------------------------------
void Server::setFatalOnError(bool fatalOnError)
{
ms_fatalOnError=fatalOnError;
}
// ----------------------------------------------------------------------
bool Server::getFatalOnError()
{
return ms_fatalOnError;
}
// ----------------------------------------------------------------------
void Server::setFatalOnDataError(bool fatalOnDataError)
{
ms_fatalOnDataError=fatalOnDataError;
}
// ----------------------------------------------------------------------
bool Server::getFatalOnDataError()
{
return ms_fatalOnDataError;
}
// ======================================================================
@@ -0,0 +1,274 @@
// ======================================================================
//
// DBServer.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_DBServer_H
#define INCLUDED_DBServer_H
// ======================================================================
#include "sharedDatabaseInterface/DbProtocol.def"
#include "sharedSynchronization/Mutex.h"
// ======================================================================
namespace DB {
class Session;
class Profiler;
/**
* The Server class handles connecting to an external database server. It knows how to establish connections,
* do error handling, etc. Create a Server object for each database you with to connect to. Then, call getSession()
* to get a Session object, which represents an individual session on the database server. Queries can be passed
* to the Session object.
*
* The Server class does session pooling. Call the Connect() method to pre-allocate some Sessions in a pool.
* getSession() will return one of the Sessions from the pool, without blocking. If the pool is empty, getSession()
* will establish a new Session, which may require some blocking while the underlying network connection is set up.
*
* The Server class is threadsafe. Servers can be shared between threads. Sessions and Queries should not be shared.
* @todo Actually, it isn't threadsafe. Need to fix that.
*/
class Server
{
/** A sub-class to hold the elements in the list of Sessions making up the Session pool
*/
struct SesListElem {
Session *ses;
SesListElem *next;
SesListElem (Session *_ses, SesListElem *_next);
};
protected:
char dsn[80],uid[80],pwd[80];
private:
/** Pool of available Sessions.
*/
SesListElem *sessionList;
Mutex sessionListLock;
bool m_useMemoryManager;
static Mutex ms_profileMutex;
static bool ms_enableProfiling;
static bool ms_enableVerboseMode;
static Profiler *ms_profiler;
static int ms_prefetchNumRows;
static int ms_prefetchMemory;
static int ms_reconnectTime;
static int ms_maxErrorCountBeforeDisconnect;
static int ms_maxErrorCountBeforeBailout;
static int ms_errorSleepTime;
static int ms_disconnectSleepTime;
static int ms_execCount;
static int ms_fetchCount;
static bool ms_fatalOnError;
static bool ms_fatalOnDataError;
public:
Server(const char *_dsn, const char *_uid, const char *_pwd, bool useMemoryManager); // TODO: should be protected?
virtual ~Server();
static Server *create(const char *_dsn, const char *_uid, const char *_pwd, Protocol protocol, bool useMemoryManager);
static Protocol getProtocolByName(const std::string &name);
Session *getSession();
void releaseSession(Session *session);
bool connect(int numSessions=1);
bool disconnect();
const char *getDSN() const;
bool getUseMemoryManager() const;
static void enableProfiling();
static void disableProfiling();
static void endProfiling();
static bool isProfilingEnabled();
static void enableVerboseMode();
static void disableVerboseMode();
static bool isVerboseModeEnabled();
static void enablePrefetch(int numRows, int memory);
static void disablePrefetch();
static bool isPrefetchEnabled();
static int getPrefetchRows();
static int getPrefetchMemory();
static void addQueryProfileData(const std::string &queryName, int execTime, int fetchTime, int execCount, int fetchCount);
static void debugOutputProfile();
static void addQueryCount(int execCount, int fetchCount);
static void getAndResetQueryCount(int &execCount, int &fetchCount);
static void setReconnectTime(int reconnectTime);
static int getReconnectTime();
static void setMaxErrorCountBeforeDisconnect(int maxErrorCountBeforeDisconnect);
static int getMaxErrorCountBeforeDisconnect();
static void setMaxErrorCountBeforeBailout(int maxErrorCountBeforeBailout);
static int getMaxErrorCountBeforeBailout();
static void setErrorSleepTime(int errorSleepTime);
static int getErrorSleepTime();
static void setDisconnectSleepTime(int disconnectSleepTime);
static int getDisconnectSleepTime();
static void setFatalOnError(bool fatalOnError);
static bool getFatalOnError();
static void setFatalOnDataError(bool fatalOnDataError);
static bool getFatalOnDataError();
protected:
virtual Session *createSession() =0;
private:
void pushSession(Session *session);
Session *popSession();
private:
Server(); //disable
Server(const Server &); //disable
Server & operator=(const Server &); //disable
}; //lint !e1712 // no default constructor for SesListElem
}
// ======================================================================
inline const char *DB::Server::getDSN() const
{
return dsn;
}
// ----------------------------------------------------------------------
inline bool DB::Server::isProfilingEnabled()
{
return ms_enableProfiling;
}
// ----------------------------------------------------------------------
inline bool DB::Server::isVerboseModeEnabled()
{
return ms_enableVerboseMode;
}
// ----------------------------------------------------------------------
inline void DB::Server::enableProfiling()
{
ms_enableProfiling = true;
}
// ----------------------------------------------------------------------
inline void DB::Server::disableProfiling()
{
ms_enableProfiling = false;
}
// ----------------------------------------------------------------------
inline void DB::Server::enableVerboseMode()
{
ms_enableVerboseMode = true;
}
// ----------------------------------------------------------------------
inline void DB::Server::disableVerboseMode()
{
ms_enableVerboseMode = false;
}
// ----------------------------------------------------------------------
inline int DB::Server::getReconnectTime()
{
return ms_reconnectTime;
}
// ----------------------------------------------------------------------
inline bool DB::Server::getUseMemoryManager() const
{
return m_useMemoryManager;
}
// ----------------------------------------------------------------------
inline void DB::Server::setMaxErrorCountBeforeDisconnect(int maxErrorCountBeforeDisconnect)
{
ms_maxErrorCountBeforeDisconnect = maxErrorCountBeforeDisconnect;
}
// ----------------------------------------------------------------------
inline int DB::Server::getMaxErrorCountBeforeDisconnect()
{
return ms_maxErrorCountBeforeDisconnect;
}
// ----------------------------------------------------------------------
inline void DB::Server::setMaxErrorCountBeforeBailout(int maxErrorCountBeforeBailout)
{
ms_maxErrorCountBeforeBailout = maxErrorCountBeforeBailout;
}
// ----------------------------------------------------------------------
inline int DB::Server::getMaxErrorCountBeforeBailout()
{
return ms_maxErrorCountBeforeBailout;
}
// ----------------------------------------------------------------------
inline void DB::Server::setErrorSleepTime(int errorSleepTime)
{
ms_errorSleepTime=errorSleepTime;
}
// ----------------------------------------------------------------------
inline int DB::Server::getErrorSleepTime()
{
return ms_errorSleepTime;
}
// ----------------------------------------------------------------------
inline void DB::Server::setDisconnectSleepTime(int disconnectSleepTime)
{
ms_disconnectSleepTime=disconnectSleepTime;
}
// ----------------------------------------------------------------------
inline int DB::Server::getDisconnectSleepTime()
{
return ms_disconnectSleepTime;
}
// ======================================================================
#endif
@@ -0,0 +1,128 @@
// ======================================================================
//
// DBSession.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbSession.h"
#include "sharedLog/Log.h"
#include <cstring>
#include <string>
#include <cassert>
#include "sharedDatabaseInterface/DbQuery.h"
#include "sharedDatabaseInterface/DbServer.h"
using namespace DB;
// ======================================================================
/**
* Do not create session objects directly.
* Instead, use DB::Server::GetSession().
*/
Session::Session() : inUse(false), connected(false), lastQuery(0), lastQueryStatement(), m_execCount(0), m_fetchCount(0), m_fatalOnError(false)
{
}
// ----------------------------------------------------------------------
Session::~Session()
{
DEBUG_FATAL(inUse,("Deleted a session that was still in use.\n"));
DEBUG_FATAL(connected,("Derived session did not disconnect."));
} //lint !e1540 // didn't delete lastQuery
// ----------------------------------------------------------------------
/**
* Execute a database query, represented by a Query object.
*/
bool Session::exec(Query *query)
{
NOT_NULL(query);
if (!inUse) // if the query was just run, we don't need to do the setup again
{
if (!query->setup(this)) return false;
}
else
{
// debugging: make sure this is the _same_ query
DEBUG_FATAL(lastQuery!=query,("Called Session::exec() on a query without calling done() on the previous query."));
}
if (!query->exec())
{
std::string context;
query->getDebugName(context);
WARNING(true, ("Context from previous database error: %s", context.c_str()));
LOG("DatabaseError", ("Context from previous database error: %s", context.c_str()));
return false;
}
lastQuery=query;
inUse=true;
return true;
}
// ----------------------------------------------------------------------
/** [Function used by other classes in the database library.] Called when a Query object finishes its work, so that
the Session is now free to run another Query.
*/
void Session::queryDone()
{
inUse=false;
lastQuery=0;
}
// ----------------------------------------------------------------------
void Session::addQueryCount(int execCount, int fetchCount)
{
m_execCount += execCount;
m_fetchCount += fetchCount;
}
// ----------------------------------------------------------------------
void Session::updateServerQueryCount()
{
Server::addQueryCount(m_execCount, m_fetchCount);
m_execCount=0;
m_fetchCount=0;
}
// ----------------------------------------------------------------------
void Session::setLastQueryStatement(std::string const & queryStatement)
{
lastQueryStatement = queryStatement;
}
// ----------------------------------------------------------------------
std::string Session::getLastQueryStatement() const
{
return lastQueryStatement;
}
// ----------------------------------------------------------------------
void Session::setFatalOnError(bool fatalOnError)
{
m_fatalOnError=fatalOnError;
}
// ----------------------------------------------------------------------
bool Session::getFatalOnError() const
{
return m_fatalOnError;
}
// ======================================================================
@@ -0,0 +1,141 @@
// ======================================================================
//
// DBSession.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_DBSession_H
#define INCLUDED_DBSession_H
// ======================================================================
#include <string>
// ======================================================================
namespace DB {
class Server;
class Query;
class QueryImpl;
/**
* A DBSession is an object representing a connection on which a series
* of queries can be performed. A database session is much like a session
* at a command prompt in an operating system. Within a session, one query
* can be sent at a time and nothing else can be done in that session until
* the results of the query are returned. A session may be thought of as a
* logical connection to the database.
*
* Do not create DBSession objects directly. Use the GetSession method on
* DBServer instead. Be sure to call DBServer::ReleaseSession() when you
* are done with the session, so that others may use it.
*
* Note that DBSession objects can't be copied. Database libraries do not
* allow a session to be cloned, so the semantics of copying a session object
* are not clear. Therefore, it is not allowed.
*
* TODO: Consider making an autoptr-like object to hold sessions. It would
* automatically call ReleaseSession() when it goes out of scope.
*/
class Session
{
bool inUse;
// following are disallowed:
Session(const Session& rhs);
Session &operator=(const Session& rhs);
protected:
bool connected;
private:
Query *lastQuery;
std::string lastQueryStatement;
int m_execCount;
int m_fetchCount;
bool m_fatalOnError;
public:
Session(); // TODO: should be private
virtual ~Session();
// functions used by other SQLClasses
void queryDone();
/** [Function used by other classes in the database library.] Establish connection to a database server.
*/
virtual bool connect() =0;
/** [Function used by other classes in the database library.] Drop connection to a database server.
*/
virtual bool disconnect() =0;
/** [Function used by other classes in the database library.] Reset the session to its default status
(e.g. before returning it to the session pool). Undo any special options the user may have set,
such as setting manual-commit mode.
If this returns false, an error occurred trying to restore the state. The best thing to do is
probably to drop the session and establish a new one.
*/
virtual bool reset() =0;
bool exec(Query *query);
/** Set the session to auto-commit or manual-commit mode.
If in auto-commit mode, every query set to Exec() is automatically
commited immediately. If in manual commit mode, the changes made
by queries passed to Exec() are considered to be part of a transaction.
They are remembered by the database, but they don't take effect
immediately. When CommitTransaction() is called, the changes all
take effect simultaneously.
(Warning: switching from manual-commit mode to auto-commit mode
automatically commits any open transactions.)
@param autocommit TRUE turns on auto-commit mode (the default),
FALSE turns on manual-commit mode
*/
virtual bool setAutoCommitMode(bool autocommit) =0;
/** Set the session to FATAL on a database error, rather than returning
"false" to the caller.
*/
void setFatalOnError(bool fatalOnError);
bool getFatalOnError() const;
/** Commit a transaction.
Everything done within the transaction will simultaneously take effect.
*/
virtual bool commitTransaction() =0;
/** Rollback a transaction
Evertyhing done within the transaction will be undone.
*/
virtual bool rollbackTransaction() =0;
/** Add to the count of the number of fetches and executes.
Each query adds to this count as it finishes.
*/
void addQueryCount(int execCount, int fetchCount);
/** Update the total count of fetches and executes in the Server object
*/
void updateServerQueryCount();
/** Set/Get the last query statement that was run; useful for debugging purposes
*/
void setLastQueryStatement(std::string const & queryStatement);
std::string getLastQueryStatement() const;
virtual QueryImpl *createQueryImpl(Query *owner) const =0;
};
}
// ======================================================================
#endif
@@ -0,0 +1,20 @@
// ======================================================================
//
// FirstServerDatabaseInterface.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_FirstServerDatabaseInterface_H
#define INCLUDED_FirstServerDatabaseInterface_H
// ======================================================================
#include "sharedFoundation/FirstSharedFoundation.h"
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedMemoryManager/FirstSharedMemoryManager.h"
// ======================================================================
#endif
@@ -0,0 +1,89 @@
// ======================================================================
//
// NullEncodedStandardString.cpp
// copyright (c) 2004 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/NullEncodedStandardString.h"
#include "Archive/Archive.h"
#include "Archive/ByteStream.h"
#include "UnicodeUtils.h"
#include "unicodeArchive/UnicodeArchive.h"
// ======================================================================
namespace NullEncodedStandardStringNamespace
{
std::string s_nullString;
std::string s_encodedNull( " " ); // blank space
}
using namespace NullEncodedStandardStringNamespace;
// ======================================================================
NullEncodedStandardString::NullEncodedStandardString(std::string const & src) :
m_value(src.empty() ? s_encodedNull : src)
{
}
// ----------------------------------------------------------------------
NullEncodedStandardString:: NullEncodedStandardString() :
m_value()
{
}
// ----------------------------------------------------------------------
void NullEncodedStandardString::setValue(std::string const & src)
{
m_value = src.empty() ? s_encodedNull : src;
}
// ----------------------------------------------------------------------
std::string const & NullEncodedStandardString::getValue() const
{
if (m_value == s_encodedNull)
return s_nullString;
else
return m_value;
}
// ----------------------------------------------------------------------
std::string const & NullEncodedStandardString::getValueEncoded() const
{
return m_value;
}
// ----------------------------------------------------------------------
void NullEncodedStandardString::setValueEncoded(std::string const & src)
{
m_value = src;
}
// ======================================================================
namespace Archive
{
void get(ReadIterator & source, NullEncodedStandardString & target)
{
std::string temp;
get(source, temp);
target.setValue(temp);
}
// ----------------------------------------------------------------------
void put(ByteStream & target, const NullEncodedStandardString & source)
{
put(target, source.getValue());
}
}
// ======================================================================
@@ -0,0 +1,47 @@
// ======================================================================
//
// NullEncodedStandardString.h
// copyright (c) 2004 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_NullEncodedStandardString_H
#define INCLUDED_NullEncodedStandardString_H
// ======================================================================
#include "Unicode.h"
// ======================================================================
/**
* A unicode-string-compatible class that encodes a null value as a single space
*/
class NullEncodedStandardString
{
public:
NullEncodedStandardString();
explicit NullEncodedStandardString(std::string const & src);
std::string const & getValue() const;
void setValue(std::string const & src);
std::string const & getValueEncoded() const;
void setValueEncoded(std::string const & src);
private:
std::string m_value;
};
// ======================================================================
namespace Archive
{
class ReadIterator;
class ByteStream;
void get(ReadIterator & source, NullEncodedStandardString & target);
void put(ByteStream & target, const NullEncodedStandardString & source);
}
// ======================================================================
#endif // INCLUDED_NullEncodedStandardString_H
@@ -0,0 +1,89 @@
// ======================================================================
//
// NullEncodedUnicodeString.cpp
// copyright (c) 2004 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/NullEncodedUnicodeString.h"
#include "Archive/Archive.h"
#include "Archive/ByteStream.h"
#include "UnicodeUtils.h"
#include "unicodeArchive/UnicodeArchive.h"
// ======================================================================
namespace NullEncodedUnicodeStringNamespace
{
Unicode::String s_nullString;
Unicode::String s_encodedNull(Unicode::narrowToWide(" "));
}
using namespace NullEncodedUnicodeStringNamespace;
// ======================================================================
NullEncodedUnicodeString::NullEncodedUnicodeString(Unicode::String const & src) :
m_value(src.empty() ? s_encodedNull : src)
{
}
// ----------------------------------------------------------------------
NullEncodedUnicodeString:: NullEncodedUnicodeString() :
m_value()
{
}
// ----------------------------------------------------------------------
void NullEncodedUnicodeString::setValue(Unicode::String const & src)
{
m_value = src.empty() ? s_encodedNull : src;
}
// ----------------------------------------------------------------------
Unicode::String const & NullEncodedUnicodeString::getValue() const
{
if (m_value == s_encodedNull)
return s_nullString;
else
return m_value;
}
// ----------------------------------------------------------------------
Unicode::String const & NullEncodedUnicodeString::getValueEncoded() const
{
return m_value;
}
// ----------------------------------------------------------------------
void NullEncodedUnicodeString::setValueEncoded(Unicode::String const & src)
{
m_value = src;
}
// ======================================================================
namespace Archive
{
void get(ReadIterator & source, NullEncodedUnicodeString & target)
{
Unicode::String temp;
get(source, temp);
target.setValue(temp);
}
// ----------------------------------------------------------------------
void put(ByteStream & target, const NullEncodedUnicodeString & source)
{
put(target, source.getValue());
}
}
// ======================================================================
@@ -0,0 +1,47 @@
// ======================================================================
//
// NullEncodedUnicodeString.h
// copyright (c) 2004 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_NullEncodedUnicodeString_H
#define INCLUDED_NullEncodedUnicodeString_H
// ======================================================================
#include "Unicode.h"
// ======================================================================
/**
* A unicode-string-compatible class that encodes a null value as a single space
*/
class NullEncodedUnicodeString
{
public:
NullEncodedUnicodeString();
explicit NullEncodedUnicodeString(Unicode::String const & src);
Unicode::String const & getValue() const;
void setValue(Unicode::String const & src);
Unicode::String const & getValueEncoded() const;
void setValueEncoded(Unicode::String const & src);
private:
Unicode::String m_value;
};
// ======================================================================
namespace Archive
{
class ReadIterator;
class ByteStream;
void get(ReadIterator & source, NullEncodedUnicodeString & target);
void put(ByteStream & target, const NullEncodedUnicodeString & source);
}
// ======================================================================
#endif
@@ -0,0 +1,42 @@
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbLogEvent.h"
#include "sharedDatabaseInterface/DbQuery.h"
#include "sharedFoundation/Os.h"
//#include "LogQueries.h"
//#include "Schema.h"
//-----------------------------------------------------------------------------
using namespace DB;
//-----------------------------------------------------------------------------
LogEvent::LogEvent() :
eventTime(Os::getRealSystemTime())
{
}
//-----------------------------------------------------------------------------
//bool TestEvent::save(DB::Session *session)
//{
// DBQuery::SaveTestEvent qry;
// DBSchema::ServerLogRow data;
// qry.setData(&data);
// qry.insertMode();
// data.event_time=eventTime;
// data.server=3434;
// data.event_id=1;
// session->exec(&qry);
// qry.done();
// return true;
//}
//-----------------------------------------------------------------------------
@@ -0,0 +1,50 @@
#ifndef _LOG_EVENT_H
#define _LOG_EVENT_H
//-----------------------------------------------------------------------------
namespace DB
{
class Session;
}
//-----------------------------------------------------------------------------
namespace DB
{
/**
* This is an abstract base class for events that can be logged.
*
* To create a LogEvent for a particular purpose, derive from this class.
* Override the save function to do whatever is needed to record the
* particular event.
*/
class LogEvent
{
public:
/**
* Default constructor stored the current system time in eventTime.
*/
LogEvent();
public:
/**
* Saves the LogEvent to the database.
*
* Override this function in derived classes to save specific data.
*/
virtual bool save(DB::Session *session) =0;
protected:
/**
* The time the event occurred, in seconds since the epoch.
*/
time_t eventTime;
};
}
//-----------------------------------------------------------------------------
#endif
@@ -0,0 +1,107 @@
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbLogger.h"
#include "sharedDatabaseInterface/DbServer.h"
#include "sharedDatabaseInterface/DbTaskQueue.h"
#include "sharedDatabaseInterface/DbTaskSaveLog.h"
//-----------------------------------------------------------------------------
using namespace DB;
//-----------------------------------------------------------------------------
Logger::EventsType Logger::events;
int Logger::maxQueuedEvents;
real Logger::maxTimeBeforeSave;
real Logger::timeSinceLastSave=0;
TaskQueue *Logger::taskQueue=0;
bool Logger::installed=false;
//-----------------------------------------------------------------------------
/**
* Set up the logger.
*
*
* @param server The database server to send events to.
* @param _maxQueuedEvents The maximum number of events that can be queued
* before a save is forced.
* @param _maxTimeBeforeSave The maximum amount of time that can pass before a
* save is forced.
*/
void Logger::install(Server *server, int _maxQueuedEvents, real _maxTimeBeforeSave)
{
maxQueuedEvents=_maxQueuedEvents;
maxTimeBeforeSave=_maxTimeBeforeSave;
//TODO: establish database connection
taskQueue=new TaskQueue(1,server,0);
installed=true;
}
//-----------------------------------------------------------------------------
void Logger::remove()
{
//TODO: wait for task queue to complete - or will destructor handle it?
delete taskQueue;
}
//-----------------------------------------------------------------------------
/**
* Add an event to the queue to be logged.
*
* @param event The event to be logged. Will be deleted when the logger is done
* with it.
*/
void Logger::log(LogEvent *event)
{
events.push_back(event);
}
//-----------------------------------------------------------------------------
/**
* Evaluates whether it is time to save the accumulated log events.
*
* This should be called periodically, i.e. once per game loop.
*
* @param time The time in seconds since this function was last invoked.
*/
void Logger::update(real time)
{
timeSinceLastSave+=time;
if ((timeSinceLastSave > 10) || (events.size() > 10))
beginSave();
}
//-----------------------------------------------------------------------------
/**
* Start an asynchronous task to save the current events.
*
* We don't care if another save is already in progress, because save tasks
* should not conflict with eachother.
*/
void Logger::beginSave()
{
if (events.size() == 0)
return;
TaskSaveLog *tsl=new TaskSaveLog;
// Copy events to the new task
for (EventsType::iterator i=events.begin(); i!=events.end(); ++i)
{
tsl->addEvent(*i);
}
events.clear();
taskQueue->asyncRequest(tsl);
} //lint !e429 // didn't free tsl
//-----------------------------------------------------------------------------
@@ -0,0 +1,64 @@
#ifndef _LOGGER_H
#define _LOGGER_H
//-----------------------------------------------------------------------------
#include <vector>
//-----------------------------------------------------------------------------
namespace DB
{
class LogEvent;
class TaskQueue;
class Server;
}
//-----------------------------------------------------------------------------
namespace DB
{
/**
* A class that organizes sending LogEvents to the database.
*
* This class will collect LogEvents and periodically send them to
* the database to be recorded.
*/
class Logger
{
public:
static void log(LogEvent *event);
// Maybe, in derived class:
// logPlayerEvent(int player, ...);
// etc.
static void update(real time);
public:
//TODO: come up with reasonable defaults for these parameters:
static void install(Server *server, int _maxQueuedEvents=10, real _maxTimeBeforeSave=10.0);
static void remove(void);
private:
static void beginSave(void);
private:
static bool installed;
static int maxQueuedEvents;
static real maxTimeBeforeSave;
typedef std::vector<LogEvent*> EventsType;
static EventsType events;
static real timeSinceLastSave;
static TaskQueue *taskQueue;
};
}
//-----------------------------------------------------------------------------
#endif
@@ -0,0 +1,47 @@
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbTaskSaveLog.h"
#include "sharedDatabaseInterface/DbLogEvent.h"
//-----------------------------------------------------------------------------
using namespace DB;
//-----------------------------------------------------------------------------
/**
* Add a LogEvent to the list to be saved.
*/
void TaskSaveLog::addEvent(LogEvent *event)
{
events.push_back(event);
}
//-----------------------------------------------------------------------------
bool TaskSaveLog::process(DB::Session *session)
{
for (EventsType::iterator i=events.begin(); i!=events.end(); ++i)
{
if(! ((*i)->save(session)))
return false;
}
return true;
}
//-----------------------------------------------------------------------------
void TaskSaveLog::onComplete()
{
}
//-----------------------------------------------------------------------------
TaskSaveLog::~TaskSaveLog()
{
for (EventsType::iterator i=events.begin(); i!=events.end(); ++i)
delete (*i);
}
//-----------------------------------------------------------------------------
@@ -0,0 +1,45 @@
#ifndef _TASK_SAVE_LOG_H
#define _TASK_SAVE_LOG_H
//-----------------------------------------------------------------------------
#include <vector>
#include "sharedDatabaseInterface/DbTaskRequest.h"
//-----------------------------------------------------------------------------
namespace DB
{
class LogEvent;
}
//-----------------------------------------------------------------------------
namespace DB
{
/**
* An asynchronous task to save a set of LogEvents.
*/
class TaskSaveLog:public DB::TaskRequest
{
public:
void addEvent(LogEvent *event);
public:
bool process(DB::Session *session);
void onComplete();
public:
virtual ~TaskSaveLog();
private:
typedef std::vector<LogEvent*> EventsType;
EventsType events;
};
}
//-----------------------------------------------------------------------------
#endif
@@ -0,0 +1,273 @@
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbTaskQueue.h"
#include "sharedDatabaseInterface/DbServer.h"
#include "sharedDatabaseInterface/DbTaskRequest.h"
#include "sharedDebug/PerformanceTimer.h"
#include "sharedFoundation/Os.h"
#include "sharedLog/Log.h"
#include "sharedThread/RunThread.h"
#include <string>
using namespace DB;
volatile int TaskQueue::sm_iTotalNumRequests = 0;
volatile int TaskQueue::sm_iTotalNumResults = 0;
bool TaskQueue::ms_workerThreadsLoggingEnabled = false;
TaskQueue::TaskQueue(unsigned int _numThreads, Server *_server, int _threadGroupId) :
numThreads(_numThreads),
server(_server),
requestQ(),
requestQLock(),
requestQAdded(requestQLock),
resultQ(),
resultQLock(),
pauseLock(),
pauseSignal(pauseLock),
workers(),
shutdown(false),
paused(false),
updateCountLock(),
activeCount(_numThreads),
idleCount(0),
threadGroupId(_threadGroupId),
numRequests(0),
numResults(0),
threadIdLock(),
nextThreadId(0)
{ //lint !e1926 // using default constructors for several members -- is intentional
for (unsigned int i=0; i<numThreads; ++i)
{
Thread * threadObject = new MemberFunctionThreadZero<TaskQueue>("DBTaskQueue", *this, &TaskQueue::workerThreadLoop);
ThreadHandle tempThreadHandle(threadObject);
workers.push_back(tempThreadHandle);
}
}
TaskQueue::~TaskQueue()
{
shutdown=true;
unpause();
requestQAdded.signal(); // get the attention of waiting threads
for(unsigned int i=0; i<numThreads; ++i)
{
workers[i]->wait();
}
while (!resultQ.empty())
{
update(0); // empty out the result queue before quitting
}
} //lint !e1740 // didn't delete server
void TaskQueue::asyncRequest(TaskRequest *req)
{
requestQLock.enter();
++numRequests;
++sm_iTotalNumRequests;
requestQ.push_front(req);
requestQAdded.signal();
requestQLock.leave();
}
void TaskQueue::workerThreadLoop()
{
threadIdLock.enter();
int threadId=nextThreadId++;
threadIdLock.leave();
Os::OsPID_t processId=Os::getProcessId();
LOG("WorkerThreads",("Thread %d-%d (%d) starting",threadGroupId,threadId,processId));
Session * session = server->getSession();
while (!shutdown)
{
TaskRequest *req;
if (ms_workerThreadsLoggingEnabled)
LOG("WorkerThreads",("Thread %d-%d (%d) about to grab a task",threadGroupId,threadId, processId));
requestQLock.enter();
updateCountLock.enter();
--activeCount;
++idleCount;
updateCountLock.leave();
while (requestQ.empty())
{
if (shutdown) // only check for shutdown when there's nothing left to do
{
// .leave and wake next thread
requestQAdded.signal(); // on shutdown, each thread wakes up the next one
updateCountLock.enter();
--idleCount;
updateCountLock.leave();
requestQLock.leave();
server->releaseSession(session);
session=0;
return;
}
if (ms_workerThreadsLoggingEnabled)
LOG("WorkerThreads",("Thread %d-%d (%d) waiting for a task",threadGroupId,threadId,processId));
requestQAdded.wait();
}
// locked
req=requestQ.back(); // FIFO: added to front, removed from back
requestQ.pop_back();
--numRequests;
--sm_iTotalNumRequests;
if (!requestQ.empty())
{
requestQAdded.signal();
}
updateCountLock.enter();
--idleCount;
++activeCount;
updateCountLock.leave();
requestQLock.leave();
// Check for the queue being paused
pauseLock.enter();
while (paused)
{
updateCountLock.enter();
++idleCount;
--activeCount;
updateCountLock.leave();
pauseSignal.wait();
updateCountLock.enter();
--idleCount;
++activeCount;
updateCountLock.leave();
}
pauseLock.leave();
NOT_NULL(session);
if (ms_workerThreadsLoggingEnabled)
LOG("WorkerThreads",("Thread %d-%d (%d) running",threadGroupId,threadId,processId));
req->workerThreadLoop(session);
if (ms_workerThreadsLoggingEnabled)
LOG("WorkerThreads",("Thread %d-%d (%d) finished a loop (about to enter resultQLock)",threadGroupId,threadId,processId));
resultQLock.enter();
if (ms_workerThreadsLoggingEnabled)
LOG("WorkerThreads",("Thread %d-%d (%d) finished a loop (entered resultQLock)",threadGroupId,threadId,processId));
++numResults;
++sm_iTotalNumResults;
if (ms_workerThreadsLoggingEnabled)
LOG("WorkerThreads",("Thread %d-%d (%d) finished a loop (incremented numResults)",threadGroupId,threadId,processId));
resultQ.push_front(req);
if (ms_workerThreadsLoggingEnabled)
LOG("WorkerThreads",("Thread %d-%d (%d) finished a loop (did resultQ.push_front)",threadGroupId,threadId,processId));
resultQLock.leave();
if (ms_workerThreadsLoggingEnabled)
LOG("WorkerThreads",("Thread %d-%d (%d) finished a loop (left resultQLock)",threadGroupId,threadId,processId));
}
server->releaseSession(session);
session=0;
}
void TaskQueue::update(float maxTime)
{
PerformanceTimer timer;
timer.start();
TaskRequest *req;
resultQLock.enter();
while (!resultQ.empty() && (maxTime==0 || timer.getSplitTime() < maxTime))
{
req=resultQ.back();
resultQ.pop_back();
--numResults;
--sm_iTotalNumResults;
resultQLock.leave();
if (req->mainThreadFinish())
{
req->mainThreadOnComplete();
delete req;
}
else
{
// if Finish() returns false, more worker thread processing is needed
asyncRequest(req);
}
resultQLock.enter();
}
resultQLock.leave();
}
void TaskQueue::cancel()
{
requestQLock.enter();
while(!requestQ.empty())
{
TaskRequest *req=requestQ.back();
delete req;
requestQ.pop_back();
}
requestQLock.leave();
}
int TaskQueue::getNumPendingTasks()
{
return numRequests;
}
int TaskQueue::getNumFinishedTasks()
{
return numResults;
}
int TaskQueue::getNumActiveTasks()
{
return activeCount;
}
void TaskQueue::report()
{
DEBUG_REPORT_LOG(true,("Task queue status: %i threads, %i active, %i idle, %i undelegated tasks\n",numThreads,activeCount,idleCount,getNumPendingTasks()));
}
bool TaskQueue::isIdle()
{
return (activeCount==0 && getNumPendingTasks()==0 && getNumFinishedTasks()==0 && !paused);
}
void TaskQueue::pause()
{
pauseLock.enter();
paused=true;
pauseLock.leave();
}
void TaskQueue::unpause()
{
pauseLock.enter();
if (paused)
{
paused=false;
pauseSignal.broadcast();
}
pauseLock.leave();
}
void TaskQueue::enableWorkerThreadsLogging(bool enabled)
{
ms_workerThreadsLoggingEnabled=enabled;
}
@@ -0,0 +1,149 @@
#ifndef _DB_TASK_QUEUE_H
#define _DB_TASK_QUEUE_H
#include <list>
#include <vector>
#include "sharedSynchronization/Mutex.h"
#include "sharedSynchronization/ConditionVariable.h"
#include "sharedThread/ThreadHandle.h"
namespace DB
{
class Server;
class Session;
class TaskRequest;
class TaskWorkerThread;
/** A class organizing a queue of requests to the database. Worker threads will
* perform the requests on a FIFO basis.
*/
class TaskQueue
{
unsigned int numThreads;
DB::Server *server;
std::list<TaskRequest*> requestQ;
Mutex requestQLock;
ConditionVariable requestQAdded;
std::list<TaskRequest*> resultQ;
Mutex resultQLock;
Mutex pauseLock;
ConditionVariable pauseSignal;
std::vector<ThreadHandle> workers;
/** Set to true when we are trying to delete the queue. Worker
* threads test this to see whether to quit.
*/
bool shutdown;
bool paused;
Mutex updateCountLock;
int activeCount;
int idleCount;
int threadGroupId;
int numRequests;
int numResults;
Mutex threadIdLock;
int nextThreadId;
static bool ms_workerThreadsLoggingEnabled;
public:
TaskQueue(unsigned int _numThreads, Server *_server, int _threadGroupId);
~TaskQueue();
/** Give a request to the task queue. It will hand the request to a
* worker thread to be processed.
*/
void asyncRequest(TaskRequest *req);
/** Called by the worker thread(s). Pops a request off the queue and
* calls Process() on the request. Sleeps until a request is added if
* there are none available.
*
* Always returns true. TODO: Add support for aborting the worker
* threads, in which case this will return false when the thread should
* stop itself.
*
* @param session A database session owned by the worker thread. It
* will be used for running any queries.
*/
void workerThreadLoop();
/**
* The user of the queue should call this periodically. It pops all
* completed tasks off of the queue and invokes their OnComplete()
* functions.
*
* @param maxTime The maximum time to spend processing, or 0 for unlimited.
* If the time limit is reached, tasks will be left on the queue for a
* later call to update() .
*/
void update(float maxTime);
/**
* Remove all pending tasks that have not been started yet.
* If a task is currently in progress, it is not affected.
*/
void cancel();
/**
* Pause the queue. No new tasks will be processed until the queue is unpaused.
*/
void pause();
/**
* Unpause the queue.
*/
void unpause();
/**
* Count the number of tasks that have not yet been assigned to a
* worker thread.
*/
int getNumPendingTasks();
/**
* Count the number of tasks that have been finished but not yet
* processed by the main thred.
*/
int getNumFinishedTasks();
/**
* Count the number of threads that are actively working on a task
*/
int getNumActiveTasks();
/**
* Return true if the task queue is not doing anything. (No active
* threads and no pending tasks.
*/
bool isIdle();
void report();
static void enableWorkerThreadsLogging(bool enabled);
static int getTotalNumRequests() { return (sm_iTotalNumRequests < 0 ? 0 : sm_iTotalNumRequests); }
static int getTotalNumResults() { return (sm_iTotalNumResults < 0 ? 0 : sm_iTotalNumResults); }
private:
TaskQueue(); //disable
TaskQueue(const TaskQueue &); //disable
TaskQueue& operator=(const TaskQueue&); //disable
static volatile int sm_iTotalNumRequests;
static volatile int sm_iTotalNumResults;
};
}
#endif
@@ -0,0 +1,101 @@
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbTaskRequest.h"
#include "sharedDatabaseInterface/DbException.h"
#include "sharedDatabaseInterface/DbServer.h"
#include "sharedDatabaseInterface/DbTestQuery.h"
#include "sharedDatabaseInterface/DbSession.h"
#include "sharedFoundation/Os.h"
#include "sharedLog/Log.h"
DB::TaskRequest::TaskRequest() :
needsProcessing(true),
errorCount(0),
reconnectErrorCount(0)
{
}
DB::TaskRequest::~TaskRequest()
{
}
void DB::TaskRequest::workerThreadLoop(DB::Session *ses)
{
int i = 0;
while (needsProcessing)
{
i++;
if (process(ses))
{
needsProcessing=false;
errorCount=0;
if (i > 1)
{
LOG("DatabaseError", ("Task succeeded after %d tries", i));
ses->setFatalOnError(false);
}
}
else
{
// save off the failed query statement from the process() that failed
// because it will be overwritten by the test query statement
std::string failedQuery = ses->getLastQueryStatement();
ses->rollbackTransaction();
Os::sleep(DB::Server::getErrorSleepTime());
DBTestQuery qry;
if (ses->exec(&qry))
{
if (qry.fetch() > 0)
{
int result;
qry.value.getValue(result);
if (result == 1)
{
// the connection is good, but the query in process() failed
errorCount++;
LOG("DatabaseError", (" -- DBTestQuery succeeded, errorCount = %d", errorCount));
if (errorCount==2)
ses->setFatalOnError(true);
continue;
}
}
}
else
LOG("DatabaseError", (" -- DBTestQuery failed, will disconnect/reconnect"));
ses->disconnect();
while (! (ses->connect()))
{
ses->disconnect();
Os::sleep(DB::Server::getDisconnectSleepTime());
};
LOG("DatabaseError", ("Database connection reestablished"));
}
}
ses->updateServerQueryCount();
ses->reset();
}
bool DB::TaskRequest::mainThreadFinish()
{
bool allDone=true;
if (!isFinished())
{
allDone=false;
needsProcessing=true;
}
return allDone;
}
void DB::TaskRequest::mainThreadOnComplete()
{
onComplete();
}
bool DB::TaskRequest::isFinished()
{
return true;
}
@@ -0,0 +1,77 @@
#ifndef _DB_TASK_REQUEST_H
#define _DB_TASK_REQUEST_H
namespace DB
{
class Session;
/** Abstract base class representing a request sent to the database task queue.
*/
class TaskRequest
{
private:
/** Flag to avoid calling Process() twice unexpectedly.
*/
bool needsProcessing;
/** Error count to prevent infinite retries of an operation that always fails.
*/
int errorCount;
int reconnectErrorCount;
/** Called by the database thread. Will invoke Process(). Do not override.
*/
void workerThreadLoop(DB::Session *session);
/** Called by the main thread. Will invoke IsFinished(). Do not override.
*/
bool mainThreadFinish();
/** Called by the main thread. Will invoke OnComplete(). Do not override.
*/
void mainThreadOnComplete();
public:
TaskRequest();
virtual ~TaskRequest();
/** Called by the database thread. Should do whatever database work
* is needed to handle the request.
*
* This will only get executed once, unless IsFinished() returns false.
*/
virtual bool process(DB::Session *session)=0;
/** Called by the main thread after Process() has completed. Should check the
* results. It should return true if the task is done, or false if the task
* should be put back on the queue for a worker thread to do more processing.
*
* It is not guaranteed that OnComplete() will be invoked if IsFinished() returns
* true, because a subtask's or parent task's IsFinished() might return false,
* requiring the whole set of tasks to be put back on the queue for the worker thread.
* Therefore, IsFinished() could be called again even after it returns true. (And, since
* things may have changed in the mean time, it may need to do its checks again.)
*
* The default implementation does nothing and returns true.
*/
virtual bool isFinished();
/** Called by the main thread (from DB::TaskQueue::Update()) after the request
* has been completed and IsFinished() has returned true. OnComplete() will only
* be invoked once.
*
* It is guaranteed that if OnComplete() is invoked at all, it will be invoked immediately
* after IsFinished() returns true. The only things that may happen between IsFinished()
* and OnComplete() is IsFinished() or OnComplete() on another task.
*
* However, it is not guaranteed that OnComplete() will be invoked at all when IsFinished()
* returns true, because subtasks might require more procssing.
*/
virtual void onComplete()=0;
friend class TaskQueue;
};
}
#endif
@@ -0,0 +1,34 @@
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
#include "sharedDatabaseInterface/DbTestQuery.h"
void DBTestQuery::getSQL(std::string &sql)
{
sql=std::string("select 1 from dual");
}
bool DBTestQuery::bindParameters()
{
return true;
}
bool DBTestQuery::bindColumns()
{
if (!bindCol(value)) return false;
return true;
}
DB::Query::QueryMode DBTestQuery::getExecutionMode() const
{
return MODE_SQL;
}
// ----------------------------------------------------------------------
DBTestQuery::DBTestQuery() :
Query(),
value()
{
}
@@ -0,0 +1,23 @@
#ifndef _DB_TEST_QUERY_H
#define _DB_TEST_QUERY_H
#include "sharedDatabaseInterface/Bindable.h"
#include "sharedDatabaseInterface/DbQuery.h"
class DBTestQuery : public DB::Query
{
public:
DB::BindableLong value;
DBTestQuery();
virtual void getSQL(std::string &sql);
virtual bool bindParameters();
virtual bool bindColumns();
virtual QueryMode getExecutionMode() const;
private: //disable
DBTestQuery(const DBTestQuery&);
DBTestQuery& operator=(const DBTestQuery&);
};
#endif
@@ -0,0 +1,9 @@
// ======================================================================
//
// FirstServerDatabaseInterface.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
@@ -0,0 +1,19 @@
/* SQLC_Defs.h
*
* This file includes common definitions needed by the other SQLClasses header files.
* (Don't include this file directly -- files that require it will include it.)
*
* Note that this file is specific to each OS, because what header files are
* needed varies in each OS. In particular, Unix versions don't want windows.h.
*
* ODBC versions: includes definitions of ODBC datatypes needed by the various
* SQLClasses
*/
#ifndef _SQLC_DEFS_H
#define _SQLC_DEFS_H
#include <windows.h>
#include <sqltypes.h>
#endif
@@ -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}
)

Some files were not shown because too many files have changed in this diff Show More