//*********************************************************************************************
#ifndef __FB_DATA_HELPER_H__
#define __FB_DATA_HELPER_H__
//*********************************************************************************************
#include "fbutils.h"
#include <vector>
#include "util.h"
#include "cmnBufferWriter.h"
//*********************************************************************************************
namespace fb {
//*********************************************************************************************
//*********************************************************************************************
static short g_nNullValue = -1;
static int g_nMaxSegmentLength = 32768;
//*********************************************************************************************
//*********************************************************************************************
//--- ISQLData Interface
//*********************************************************************************************
struct ISQLData
{
virtual ~ISQLData(){}
virtual char* get() =0;
virtual int type() const =0;
virtual int size() const =0;
virtual void fill ( XSQLVAR* pXSQLVAR, isc_db_handle* pDatabaseConnection, isc_tr_handle* pCurrentTransaction ) = 0;
virtual void prepare ( XSQLVAR* pXSQLVAR ) = 0;
virtual void serialize ( cmn::BufferWriter& cmnBufferWriter, isc_db_handle* pDatabaseConnection, isc_tr_handle* pCurrentTransaction ) = 0;
};
//*********************************************************************************************
//--- CSQLData Implementation ( base types )
//*********************************************************************************************
template<class Type>
class CSQLData: public ISQLData
{
Type m_data;
int m_type;
short m_flag0;
public:
CSQLData(int type) : m_type(type),m_flag0(0){}
CSQLData(int type, const Type& data) : m_type(type), m_data(data), m_flag0(0) {}
char* get()
{
return (char*)&m_data;
}
int type() const
{
return m_type;
}
void fill ( XSQLVAR* pXSQLVAR, isc_db_handle* , isc_tr_handle* )
{
pXSQLVAR->sqldata = get();
pXSQLVAR->sqlind = &m_flag0;
pXSQLVAR->sqltype = type() + 1;
pXSQLVAR->sqllen = size();
}
void prepare ( XSQLVAR* pXSQLVAR )
{
pXSQLVAR->sqldata = get();
pXSQLVAR->sqlind = &m_flag0;
}
void serialize ( cmn::BufferWriter& cmnBufferWriter, isc_db_handle* , isc_tr_handle* )
{
cmnBufferWriter.write_value ( m_data );
}
int size() const { return sizeof(Type); }
void set_size(int size){}
};
//*********************************************************************************************
//--- CSQLData Implementation ( timestmap )
//*********************************************************************************************
template<>
class CSQLData< ISC_TIMESTAMP > : public ISQLData
{
ISC_TIMESTAMP m_data;
int m_type;
short m_flag0;
public:
CSQLData(int type) : m_type(type), m_flag0(0)
{
}
CSQLData(int type, double varTime ) : m_type(type), m_flag0(0)
{
if ( varTime == 0.0 )
m_flag0 = -1;
else
{
SYSTEMTIME stTime;
::VariantTimeToSystemTime ( varTime, &stTime );
tm tmTime;
SystemTimeToTmTime ( stTime, &tmTime );
isc_encode_timestamp ( &tmTime, &m_data );
}
}
char* get()
{
return (char*)&m_data;
}
int type() const
{
return m_type;
}
void fill ( XSQLVAR* pXSQLVAR, isc_db_handle* , isc_tr_handle* )
{
pXSQLVAR->sqldata = get();
pXSQLVAR->sqlind = &m_flag0;
pXSQLVAR->sqltype = type() + 1;
pXSQLVAR->sqllen = size();
}
void prepare ( XSQLVAR* pXSQLVAR )
{
pXSQLVAR->sqldata = get();
pXSQLVAR->sqlind = &m_flag0;
}
void serialize ( cmn::BufferWriter& cmnBufferWriter, isc_db_handle* , isc_tr_handle* )
{
tm tmTime;
isc_decode_timestamp ( &m_data, &tmTime );
SYSTEMTIME stTime;
TmTimeToSystemTime ( tmTime, &stTime );
double varTime;
::SystemTimeToVariantTime ( &stTime, &varTime );
cmnBufferWriter.write_double ( varTime );
}
int size() const { return sizeof(ISC_TIMESTAMP); }
void set_size(int size){}
};
//*********************************************************************************************
//--- CSQLData Implementation ( string types )
//*********************************************************************************************
typedef enum { ctString = 1, ctWstring, ctVector } CppType;
//*********************************************************************************************
template<>
class CSQLData< char* > : public ISQLData
{
char* m_data;
int m_type;
int m_size;
short m_flag0;
CppType m_cppType;
void init ( int f_nSize, const char* f_pData, bool fUseTypedescriptor = false)
{
m_size = f_nSize;
if ( m_type == SQL_VARYING )
{
m_data = new char[m_size+2];
short int size = (short int)m_size;
::memcpy(m_data, &size, 2);
::memcpy(m_data+2, f_pData, m_size);
m_size+=2;
}
else
{
int addSize = ctWstring ? 2 : 1;
m_data = new char[ m_size + addSize ];
::memcpy(m_data, f_pData, m_size);
if ( m_cppType == ctWstring )
{
wchar_t end[] = L"\0";
::memcpy(m_data+m_size, end, addSize);
}
else
{
char end[] = "\0";
::memcpy(m_data+m_size, end, addSize);
}
m_size+=addSize;
}
}
public:
CSQLData(int type, CppType cppType ) : m_type(type), m_size(0), m_data(0), m_flag0(0), m_cppType (cppType)
{
}
CSQLData(int type, const std::string& str ) : m_type(type), m_size(0), m_flag0(0), m_data(0), m_cppType(ctString)
{
init ( (int)str.size (), str.c_str () );
}
CSQLData(int type, const std::wstring& str ) : m_type(type), m_size(0), m_flag0(0), m_data(0), m_cppType(ctWstring)
{
init ( (int)str.size () , (const char*)utils::wstring2string(str).c_str () );
}
CSQLData(int type, const std::vector< char >& str ) : m_type(type), m_size(0), m_flag0(0), m_data(0), m_cppType(ctVector)
{
init ( (int)str.size (), utils::GetBeginOf (str), true );
}
~CSQLData()
{
if(m_data != 0)
delete []m_data;
}
char* get()
{
return m_data;
}
void prepare ( XSQLVAR* pXSQLVAR )
{
int size = pXSQLVAR->sqllen;
if(m_data == NULL)
{
if ( m_type == SQL_VARYING )
m_size = size + 2;
m_data = new char[m_size];
ZeroMemory(m_data, m_size);
}
else
throw std::runtime_error("CSQLData< char* >::Reserve");
pXSQLVAR->sqldata = get();
pXSQLVAR->sqlind = &m_flag0;
}
void fill ( XSQLVAR* pXSQLVAR, isc_db_handle* , isc_tr_handle* )
{
pXSQLVAR->sqldata = get();
pXSQLVAR->sqlind = &m_flag0;
pXSQLVAR->sqltype = type() + 1;
pXSQLVAR->sqllen = size();
}
void serialize ( cmn::BufferWriter& cmnBufferWriter, isc_db_handle* , isc_tr_handle* )
{
if ( m_cppType == ctWstring )
{
if ( m_type == SQL_VARYING )
{
std::string str;
str.assign ( m_data+2, *(short*)m_data );
std::wstring wRes = utils::string2wstring(str);
wRes.resize( *(short*)m_data);
cmnBufferWriter.write_wstring2 ( wRes );
}
else
{
std::wstring str ( (wchar_t*)m_data );
cmnBufferWriter.write_wstring2 ( str );
}
}
else if ( m_cppType == ctString )
{
if ( m_type == SQL_VARYING )
{
std::string str;
str.assign ( m_data+2, *(short*)m_data );
cmnBufferWriter.write_string_as_wstring( str );
}
else
{
std::string str (m_data);
cmnBufferWriter.write_string_as_wstring ( str );
}
}
else
{
if ( m_type == SQL_VARYING )
{
cmnBufferWriter.write_buffer ( m_data+2, *(short*)m_data );
}
else
{
std::string str (m_data);
cmnBufferWriter.write_buffer ( m_data, str.size () );
}
}
}
int type() const { return m_type; }
int size() const
{
return m_size;
}
};
//*********************************************************************************************
//--- CSQLData Implementation ( blob types )
//*********************************************************************************************
template<>
class CSQLData< std::vector< char > > : public ISQLData
{
int m_type;
int m_subtype;
short m_flag0;
std::vector< char > m_binary;
ISC_QUAD m_idBlob;
private:
void blob_write ( isc_blob_handle* phBlob, std::vector< char >& binary )
{
ISC_STATUS_ARRAY status;
int nBufferSize = (int)binary.size ();
int nSegmentSize = g_nMaxSegmentLength;
int nCurrenPos = 0;
while ( nCurrenPos + nSegmentSize < nBufferSize )
{
if ( isc_put_segment ( status, phBlob, nSegmentSize, &binary[ nCurrenPos ] ) )
throw std::runtime_error ( FormatError (status, "isc_put_segment" ) );
nCurrenPos += nSegmentSize;
}
if ( isc_put_segment ( status, phBlob, nBufferSize - nCurrenPos, &binary[ nCurrenPos ] ) )
throw std::runtime_error ( FormatError (status, "isc_put_segment" ) );
}
void blob_read ( isc_blob_handle* phBlob, std::vector< char >& binary )
{
ISC_STATUS_ARRAY status;
char arrItemList[1] = { isc_info_blob_total_length };
char bufRes [16];
if ( isc_blob_info ( status, phBlob,
sizeof (arrItemList), arrItemList,
sizeof (bufRes), bufRes ) )
{
throw std::runtime_error ( FormatError ( status, "isc_blob_info" ) );
}
long nBlobSize = isc_vax_integer ( &bufRes[3], *(short*)&bufRes[1] );
if ( nBlobSize == 0 )
return;
else
binary.resize ( nBlobSize );
long nCurrenPos = 0;
unsigned short nBytesRead = 0;
do
{
if ( isc_get_segment ( status, phBlob,
&nBytesRead,
g_nMaxSegmentLength,
&binary[ nCurrenPos ] ))
{
throw std::runtime_error ( FormatError ( status, "isc_get_segment" ) );
}
nCurrenPos += nBytesRead;
} while ( nCurrenPos < nBlobSize );
}
public:
CSQLData(int type, int subtype ) : m_type(type), m_subtype(subtype), m_binary(), m_flag0(0){}
CSQLData(int type, int subtype, std::vector< char >& binary ) : m_type(type), m_subtype(subtype), m_binary (), m_flag0(0)
{
m_binary.swap (binary);
}
~CSQLData()
{
}
char* get()
{
return utils::GetBeginOf ( m_binary );
}
void fill ( XSQLVAR* pXSQLVAR, isc_db_handle* pDatabaseConnection, isc_tr_handle* pCurrentTransaction )
{
ISC_STATUS_ARRAY status;
isc_blob_handle hBlob = NULL;
if ( isc_create_blob2 ( status
, pDatabaseConnection, pCurrentTransaction
, &hBlob, &m_idBlob
, 0, 0 ) )
{
throw std::runtime_error ( FormatError (status, "isc_create_blob2" ) );
}
CBlobGuard hBlobGuard ( hBlob );
if ( m_binary.empty () )
m_flag0 = g_nNullValue;
else
blob_write ( &hBlob, m_binary );
pXSQLVAR->sqldata = (char*)&m_idBlob;
pXSQLVAR->sqlind = &m_flag0;
pXSQLVAR->sqltype = type() + 1;
pXSQLVAR->sqllen = sizeof (m_idBlob);
}
void prepare ( XSQLVAR* pXSQLVAR )
{
pXSQLVAR->sqldata = (char*)&m_idBlob;
pXSQLVAR->sqlind = &m_flag0;
}
void serialize ( cmn::BufferWriter& cmnBufferWriter, isc_db_handle* pDatabaseConnection, isc_tr_handle* pCurrentTransaction )
{
if ( m_flag0 == g_nNullValue )
{
if ( m_subtype == 1 )
cmnBufferWriter.write_wstring ( L"" );
else
cmnBufferWriter.write_buffer ( 0, 0 );
return;
}
ISC_STATUS_ARRAY status;
isc_blob_handle hBlob = NULL;
if ( isc_open_blob2 ( status,
pDatabaseConnection, pCurrentTransaction,
&hBlob, &m_idBlob,
0, 0 ) )
{
throw std::runtime_error ( FormatError ( status, "isc_open_blob2" ) );
}
CBlobGuard hBlobGuard (hBlob);
blob_read ( &hBlob, m_binary );
if ( m_subtype == 1 )
{
if ( m_binary.empty () )
{
cmnBufferWriter.write_wstring2 ( L"" );
}
else
{
std::wstring wstr;
wstr.assign ( (wchar_t*)&m_binary[0], m_binary.size () / 2 );
cmnBufferWriter.write_wstring2 ( wstr );
}
}
else
{
if ( m_binary.empty () )
cmnBufferWriter.write_buffer ( 0, 0 );
else
cmnBufferWriter.write_buffer ( &m_binary[0], m_binary.size () );
}
}
int type() const { return m_type; }
int size() const
{
return (int)m_binary.size ();
}
};
//*********************************************************************************************
//--- CDataHelperArray Declaration
//*********************************************************************************************
class CDataHelperArray
{
std::vector< ISQLData* > m_data;
public:
~CDataHelperArray();
public:
void fill( XSQLDA* p_xsqlda, isc_db_handle* pDatabaseConnection, isc_tr_handle* pCurrentTransaction );
void prepare( XSQLDA* p_xsqlda );
void serialize ( cmn::BufferWriter& cmnBufferWriter, isc_db_handle* pDatabaseConnection, isc_tr_handle* pCurrentTransaction );
ISQLData* operator [] (unsigned int index);
int size();
void insert ( std::auto_ptr<ISQLData> pData );
};
//*********************************************************************************************
}//namespace fb
//*********************************************************************************************
#endif
//*********************************************************************************************