Click here to Skip to main content
15,879,096 members
Articles / Database Development / SQL Server

High Performance OLE DB library : Ease of ADO, power of OLE DB

Rate me:
Please Sign up or sign in to vote.
2.50/5 (6 votes)
2 Dec 20013 min read 83.2K   3.4K   41  
Introduction to OLE DB extended classes
// 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

//****************************************************************************************

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions