// SypODLObjects.h: interface for the CSypODLObjects class.
//
//////////////////////////////////////////////////////////////////////
//
// CSypODLObjects are set of classes that provide a very rich,
// sophisticated, and user-friendly wrappers around ATL consumer
// templates for OLEDB. These classes provide a lot of flexibility and
// functionality over OLEDB templates without loosing their power and
// performance
//
// Author: G. Naik, GNaik@SypramTech.com (or Ghannaik@yahoo.com)
// You may freely use these classes in non-commercial products.These
// library is not to be sold for profit.
//
// NOTE : Prior permission required by Sypram Technology (www.sypram.com)
// if you want to use this library in commercial projects. Send me an email
// if that is the case.
//
// CopyRight(C)2001. Sypram Technology. WWW.SYPRAM.COM
// Version : 1.0
//////////////////////////////////////////////////////////////////////
#if !defined(SYPOLEDB_DEFINED)
#define SYPOLEDB_DEFINED
#include "SypODLResource.h"
#include <comdef.h>
#include <atlbase.h>
#include <atldbcli.h>
#include <oledb.h>
#include <OleDBErr.h>
#include<adoid.h>
#include<adoint.h>
#define SYPODL_COMMANDTYPE_TABLE 1
#define SYPODL_COMMANDTYPE_QUERY 2
#define SYPODL_COMMANDTYPE_STORED 2
#define SYPODL_RECORDSETTYPE_FORWARDONLY 1
//******* GENERIC FUNCTIONS ***********
DATE DateFromDBTS(DBTIMESTAMP dbts);
DBTIMESTAMP DBTSFromDate(DATE dtSrc);
DBDATE DBDateFromDBTS(DBTIMESTAMP dtSrc);
DBTIMESTAMP DBTSFromDBDate(DBDATE mDDRet);
DBTIME DBTimeFromDBTS(DBTIMESTAMP dtSrc);
DBTIMESTAMP DBTSFromDBTime(DBTIME mDDRet);
LPCTSTR GetDataTypeName(WORD dbtype);
//****************************************************************************************
class CSypODLException
{
UINT m_nCause;
HRESULT m_nHr;
CComPtr<IUnknown> m_pUnknown;
public:
CSypODLException(UINT _m_cause, HRESULT hr=0, CComPtr<IUnknown> m_spUnk=0);
void DisplayError();
void GetError(CString&);
};
//****************************************************************************************
class CSypODLError
{
public:
CSypODLError();
virtual ~CSypODLError();
CString GetErrorCtx();
CString GetErrorLoc();
CString GetErrorMsg();
void ClearErrors();
protected:
virtual void SetError(CString msg, CString loc, CString ctx);
CString mErrCtx;
CString mErrLoc;
CString mErrMsg;
};
//****************************************************************************************
class CSypODLConnection : public CSypODLError
{
private:
CDataSource m_db;
CString m_Provider;
CString m_DSN;
CString m_UID;
CString m_PWD;
HRESULT hr;
bool m_bIsOpen;
public:
CSession m_session;
bool m_bEnableThrow;
public:
CSypODLConnection();
~CSypODLConnection();
void SetProvider(CString);
bool Open(CString m_DSN, CString m_UID, CString m_PWD);
bool Open(CDBPropSet);
bool IsOpen();
void Close();
bool StartTransaction(ISOLEVEL isoLevel=ISOLATIONLEVEL_READCOMMITTED, ULONG isoFlags=0);
bool Abort(BOID *pboidReason=NULL);
bool Commit(BOOL bRetaining=FALSE, DWORD grfTC=XACTTC_SYNC, DWORD grfRM=0);
bool Execute(CString sSQL);
};
//****************************************************************************************
const ULONG BUFFERSIZE = 5000;
template <typename TAccessor, typename TRowset=CRowset>
class CSypODLRecordBase : public CSypODLError
{
friend class CSypODLConnection;
protected:
bool m_bIsOpen;
UINT m_nRowsetType;
HRESULT hr;
bool m_bEOF, m_bBOF;
bool m_bHasClientCursor;
CAccessorRowset<TAccessor, TRowset> *m_pSet;
DBCOLUMNINFO *m_pColsInfo;
ULONG m_nColCount;
LPOLESTR m_pStrBuffer;
CBookmark<4> m_BK;
public:
bool m_bEnableThrow;
public:
//===============================================================================
CSypODLRecordBase()
{
m_pColsInfo = 0;
m_pStrBuffer = 0;
m_nColCount = 0;
m_pSet = 0;
m_bEnableThrow = true;
m_bIsOpen = false;
m_nRowsetType = 0;
m_bEOF = false;
m_bBOF = false;
m_bHasClientCursor = true;
}
//===============================================================================
bool IsEOF()
{
//=== Check if recordset is open
if(!m_bIsOpen)
{
ThrowError(IDS_SYPODL_ERR_RECORDSETNOTOPEN);
return false;
}
return m_bEOF;
}
//===============================================================================
bool IsBOF()
{
//=== Check if recordset is open
if(!m_bIsOpen)
{
ThrowError(IDS_SYPODL_ERR_RECORDSETNOTOPEN);
return false;
}
return m_bBOF;
}
//===============================================================================
virtual ~CSypODLRecordBase()
{
if (m_pColsInfo != 0)
CoTaskMemFree(m_pColsInfo);
if (m_pStrBuffer != 0)
CoTaskMemFree(m_pStrBuffer);
Close();
if(m_pSet != 0)
delete m_pSet;
}
//===============================================================================
TAccessor *GetAccessor()
{
return (TAccessor *) m_pSet;
}
//===============================================================================
bool IsOpen()
{
return m_bIsOpen;
}
//===============================================================================
void Close()
{
if(m_bIsOpen)
{
m_pSet->Close();
m_bIsOpen = false;
m_bEOF = false;
m_bBOF = false;
}
}
//===============================================================================
virtual bool Open(CString sCommand, CSypODLConnection *pCnn, UINT nCommandType=2, UINT nRecordsetType=0)
{
Close(); // Close recordset if already open
//=== Check if database is open
if(!pCnn->IsOpen())
{
throw CSypODLException(IDS_SYPODL_ERR_DBNOTOPEN, 0);
return false;
}
//=== Allocate buffer if not already done so
if(m_pSet == 0)
{
if(nCommandType == 2)
m_pSet = new CCommand<TAccessor, TRowset>;
else
m_pSet = new CTable<TAccessor, TRowset>;
}
CDBPropSet propset(DBPROPSET_ROWSET);
if(nRecordsetType != SYPODL_RECORDSETTYPE_FORWARDONLY)
propset.AddProperty(DBPROP_IRowsetScroll, true);
if(m_bHasClientCursor)
propset.AddProperty(DBPROP_CLIENTCURSOR, true);
propset.AddProperty(DBPROP_IRowsetChange, true);
propset.AddProperty(DBPROP_UPDATABILITY, DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE);
//=== Make sure that same type of recordset is opened repetitively
if(m_nRowsetType != 0 && m_nRowsetType != nCommandType)
{
ThrowError(IDS_SYPODL_ERR_INVALIDCHANGETYPE, 0);
return false;
}
//=== Open appropriate recordset type
if(nCommandType == 2)
{
hr = ((CCommand<TAccessor, TRowset> *)m_pSet)->Open(pCnn->m_session, sCommand, &propset);
m_nRowsetType = 2;
}
else
{
hr = ((CTable<TAccessor, TRowset> *)m_pSet)->Open(pCnn->m_session, sCommand, &propset);
m_nRowsetType = 1;
}
//=== Process result
if(FAILED(hr))
{
ThrowError(IDS_SYPODL_ERR_OPENRECORDSET, hr);
return false;
}
//=== Populate column info structure
hr = m_pSet->GetColumnInfo(&m_nColCount, &m_pColsInfo, &m_pStrBuffer);
if(FAILED(hr))
{
ThrowError(IDS_SYPODL_ERR_GETROWCOUNT, hr);
return false;
}
//=== Move recordset to the first record
MoveToFirstRecord();
m_bIsOpen = true;
return true;
}
//===============================================================================
virtual bool Open(CDBPropSet *propset, CString sCommand, CSypODLConnection *pCnn, UINT nCommandType=2)
{
Close(); // Close recordset if already open
//=== Check if database is open
if(!pCnn->IsOpen())
{
throw CSypODLException(IDS_SYPODL_ERR_DBNOTOPEN, 0);
return false;
}
//=== Allocate buffer if not already done so
if(m_pSet == 0)
{
if(nCommandType == 2)
m_pSet = new CCommand<TAccessor, TRowset >;
else
m_pSet = new CTable<TAccessor, TRowset >;
}
//=== Make sure that same type of recordset is opened repetitively
if(m_nRowsetType != 0 && m_nRowsetType != nCommandType)
{
ThrowError(IDS_SYPODL_ERR_INVALIDCHANGETYPE, 0);
return false;
}
//=== Open appropriate recordset type
if(nCommandType == 2)
{
hr = ((CCommand<TAccessor, TRowset> *)m_pSet)->Open(pCnn->m_session, sCommand, propset);
m_nRowsetType = 2;
}
else
{
hr = ((CTable<TAccessor, TRowset> *)m_pSet)->Open(pCnn->m_session, sCommand, propset);
m_nRowsetType = 1;
}
//=== Process result
if(FAILED(hr))
{
ThrowError(IDS_SYPODL_ERR_OPENRECORDSET, hr);
return false;
}
//=== Populate column info structure
hr = m_pSet->GetColumnInfo(&m_nColCount, &m_pColsInfo, &m_pStrBuffer);
if(FAILED(hr))
{
ThrowError(IDS_SYPODL_ERR_GETROWCOUNT, hr);
return false;
}
//=== Move recordset to the first record
MoveToFirstRecord();
m_bIsOpen = true;
return true;
}
//===============================================================================
bool Insert()
{
if(!m_bIsOpen)
{
ThrowError(IDS_SYPODL_ERR_RECORDSETNOTOPEN);
return false;
}
hr = m_pSet->Insert();
if(FAILED(hr))
{
ThrowError(IDS_SYPODL_ERR_INSERTRECORD, hr);
return false;
}
return true;
}
//===============================================================================
bool SetData()
{
if(!m_bIsOpen)
{
ThrowError(IDS_SYPODL_ERR_RECORDSETNOTOPEN);
return false;
}
hr = m_pSet->SetData();
if(FAILED(hr))
{
ThrowError(IDS_SYPODL_ERR_EDITRECORD, hr);
return false;
}
return true;
}
//===============================================================================
bool Delete()
{
if(!m_bIsOpen)
{
ThrowError(IDS_SYPODL_ERR_RECORDSETNOTOPEN);
return false;
}
hr = m_pSet->Delete();
if(FAILED(hr))
{
ThrowError(IDS_SYPODL_ERR_DELETERECORD, hr);
return false;
}
return true;
}
//===============================================================================
bool Update()
{
if(!m_bIsOpen)
{
ThrowError(IDS_SYPODL_ERR_RECORDSETNOTOPEN);
return false;
}
hr = m_pSet->Update();
if(FAILED(hr))
{
ThrowError(IDS_SYPODL_ERR_UPDATEROWSET, hr);
return false;
}
return true;
}
//===============================================================================
bool MoveNext()
{
if(!m_bIsOpen)
{
ThrowError(IDS_SYPODL_ERR_RECORDSETNOTOPEN);
return false;
}
hr = ((CRowset *)m_pSet)->MoveNext();
if(hr == S_OK)
m_bBOF = false;
else
m_bEOF = true;
return GetMoveStatus(hr);
}
//===============================================================================
bool MovePrev()
{
if(!m_bIsOpen)
{
ThrowError(IDS_SYPODL_ERR_RECORDSETNOTOPEN);
return false;
}
hr = ((CRowset *)m_pSet)->MovePrev();
if(hr == S_OK)
m_bEOF = false;
else
m_bBOF = true;
return GetMoveStatus(hr);
}
//===============================================================================
bool MoveFirst()
{
if(!m_bIsOpen)
{
ThrowError(IDS_SYPODL_ERR_RECORDSETNOTOPEN);
return false;
}
hr = ((CRowset *)m_pSet)->MoveFirst();
if(hr == S_OK)
{
m_bBOF = false;
m_bEOF = false;
}
else
{
m_bBOF = true;
m_bEOF = true;
}
return GetMoveStatus(hr);
}
//===============================================================================
bool MoveLast()
{
if(!m_bIsOpen)
{
ThrowError(IDS_SYPODL_ERR_RECORDSETNOTOPEN);
return false;
}
hr = ((CRowset *)m_pSet)->MoveLast();
if(hr == S_OK)
{
m_bBOF = false;
m_bEOF = false;
}
else
{
m_bBOF = true;
m_bEOF = true;
}
return GetMoveStatus(hr);
}
//===============================================================================
virtual ULONG GetRecordCount()
{
if(!m_bIsOpen)
{
ThrowError(IDS_SYPODL_ERR_RECORDSETNOTOPEN);
return -1;
}
ULONG mRecCount;
hr = ((CRowset *)m_pSet)->GetApproximatePosition(NULL, NULL, &mRecCount);
if(FAILED(hr))
{
ThrowError(IDS_SYPODL_ERR_GETROWCOUNT, hr);
return -1;
}
return mRecCount;
}
//===============================================================================
ULONG GetColumnCount()
{
if(!m_bIsOpen)
{
ThrowError(IDS_SYPODL_ERR_RECORDSETNOTOPEN);
return -1;
}
if(m_pColsInfo[0].iOrdinal == 0)
return m_nColCount-1;
else
return m_nColCount;
}
//===============================================================================
void GetColumnName(UINT index, TCHAR *pChar)
{
if(!m_bIsOpen)
{
ThrowError(IDS_SYPODL_ERR_RECORDSETNOTOPEN);
return;
}
if(index < 1 || index > GetColumnCount())
{
ThrowError(IDS_SYPODL_ERR_INVALIDCOLINDEX);
return;
}
wcscpy(pChar, m_pColsInfo[GetColumnIndex(index)].pwszName);
}
//===============================================================================
CString GetColumnName(UINT index)
{
if(!m_bIsOpen)
{
ThrowError(IDS_SYPODL_ERR_RECORDSETNOTOPEN);
return "";
}
if(index < 1 || index > GetColumnCount())
{
ThrowError(IDS_SYPODL_ERR_INVALIDCOLINDEX);
return "";
}
return CString(m_pColsInfo[GetColumnIndex(index)].pwszName);
}
//===============================================================================
int GetColumnType(UINT index, CString& pChar)
{
if(!m_bIsOpen)
{
ThrowError(IDS_SYPODL_ERR_RECORDSETNOTOPEN);
return -1;
}
if(index < 1 || index > GetColumnCount())
{
ThrowError(IDS_SYPODL_ERR_INVALIDCOLINDEX);
return -1;
}
pChar = GetDataTypeName(m_pColsInfo[index].wType);
return (m_pColsInfo[GetColumnIndex(index)].wType);
}
//===============================================================================
bool AttachADORecordset(CComPtr<ADORecordset>& pRs)
{
if(!m_bIsOpen)
{
ThrowError(IDS_SYPODL_ERR_RECORDSETNOTOPEN);
return false;
}
if(!pRs)
{
hr = pRs.CoCreateInstance(CLSID_CADORecordset);
if(FAILED(hr))
{
ThrowError(IDS_SYPODL_ERR_CREATERECORDSET, hr);
return false;
}
}
CComPtr<ADORecordsetConstruction> spADOsCt;
hr = pRs->QueryInterface(__uuidof(ADORecordsetConstruction),(void**)&spADOsCt);
if(FAILED(hr))
{
ThrowError(IDS_SYPODL_ERR_CONSTRUCTRECORDSET, hr);
return false;
}
hr= spADOsCt->put_Rowset(m_pSet->m_spRowset);
if(FAILED(hr))
{
ThrowError(IDS_SYPODL_ERR_ATTACHROWSET, hr);
return false;
}
return true;
}
//===============================================================================
bool SetBookmark(ULONG& mBookmarkPosition)
{
if(!m_bIsOpen)
{
ThrowError(IDS_SYPODL_ERR_RECORDSETNOTOPEN);
return false;
}
hr = m_pSet->GetApproximatePosition(&m_BK, &mBookmarkPosition, NULL);
if(FAILED(hr))
{
ThrowError(IDS_SYPODL_ERR_SETBOOKMARK, hr);
return false;
}
return true;
}
//===============================================================================
bool MoveToBookmark(ULONG mBookmarkPosition)
{
if(!m_bIsOpen)
{
ThrowError(IDS_SYPODL_ERR_RECORDSETNOTOPEN);
return false;
}
ULONG mRecCount;
hr = m_pSet->MoveToBookmark(m_BK, mBookmarkPosition);
if(FAILED(hr))
{
ThrowError(IDS_SYPODL_ERR_MOVETOBOOKMARK, hr);
return false;
}
return true;
}
//===============================================================================
void GetChunk(ISequentialStream* pISequentialStream, BYTE *buffer)
{
BYTE rgBuffer[BUFFERSIZE];
ULONG cb;
ULONG TotalBytes = 0;
HRESULT hr;
do
{
hr = pISequentialStream->Read(rgBuffer, BUFFERSIZE, &cb);
if (cb > 0 || hr == S_OK)
{
memcpy(buffer + TotalBytes, rgBuffer, cb);
TotalBytes += cb;
}
} while (cb >= sizeof(rgBuffer));
}
//===============================================================================
ULONG GetChunkSize(ISequentialStream* pISequentialStream)
{
BYTE rgBuffer[BUFFERSIZE];
ULONG cb;
ULONG TotalBytes = 0;
HRESULT hr;
do
{
hr = pISequentialStream->Read(rgBuffer, BUFFERSIZE, &cb);
if (cb > 0 || hr == S_OK)
TotalBytes += cb;
} while (cb >= sizeof(rgBuffer));
return TotalBytes;
}
//===============================================================================
protected:
void ThrowError(UINT m_cause, HRESULT hr=0)
{
if(m_bEnableThrow)
{
if(m_nRowsetType == 1 || !m_bIsOpen)
throw CSypODLException(m_cause, hr);
else
{
CCommand<TAccessor > *pCmd = (CCommand<TAccessor > *)m_pSet;
throw CSypODLException(m_cause, hr, (CComPtr<struct IUnknown>)pCmd->m_spCommand);
}
}
}
//===============================================================================
virtual bool GetMoveStatus(HRESULT hr)
{
if(FAILED(hr))
{
ThrowError(IDS_SYPODL_ERR_NAVIGATERECORD, hr);
return false;
}
if(SUCCEEDED(hr))
{
if(hr == S_OK)
return true;
}
return false;
}
//===============================================================================
void MoveToFirstRecord()
{
hr = ((CRowset *)m_pSet)->MoveFirst();
if(!GetMoveStatus(hr))
{
m_bBOF = true;
m_bEOF = true;
}
else
m_bBOF = false;
}
//===============================================================================
UINT GetColumnIndex(UINT index)
{
if(m_pColsInfo[0].iOrdinal == 0)
return index;
else
return (index - 1);
}
};
//****************************************************************************************
class CSypOLEDBErr
{
public:
bool AreDBErrorsSupported(CComPtr<IUnknown> m_spUnk);
bool GetDBErrors(CComPtr<IUnknown> m_spUnk, TCHAR *msg);
void GetHRRESULTMessage(HRESULT hr, TCHAR *msg);
bool GetSingleError(TCHAR *msg);
bool GetSQLCodes(TCHAR *msg, CDBErrorInfo *errInfo, ULONG errorNum = 0);
};
#endif
//****************************************************************************************