Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: C++ ATL WTL ODBC
In order to further explore ODBC and increase my programming experience i was going to put together my own ODBC wrapper classes. Below are the wrapper classes i have made so far and i'm curious on any problems anyone happens to see with it Smile | :) thanks for the help and cheers
 
template<class TDerived, SQLSMALLINT THandle = SQL_HANDLE_UNKNOWN>
class __declspec(novtable) CHandle 
{
public:
	SQLHANDLE   m_h;
	SQLSMALLINT m_hType;
 
	enum { SQL_HANDLE_UNKNOWN = -1 };
 
public:
	CHandle() : 
		m_h(NULL), m_hType(THandle)
	{
		_ASSERTE(m_hType != -1);
	}
 
	
	CHandle(SQLHANDLE h) :
		m_h(h), m_hType(THandle)
	{
		_ASSERTE(h != NULL);
		_ASSERTE(m_hType != -1);
		
		Attach(h);
	}
 
	void Attach(_In_ SQLHANDLE h)
	{
		_ASSERTE(h != NULL);
		_ASSERTE(m_h == NULL);
		_ASSERTE(m_hType != -1);
		
		m_h = h;
	}
 
	SQLHANDLE Detach()
	{
		_ASSERTE(m_h != NULL);
		_ASSERTE(m_hType != -1);
		SQLHANDLE hTemp = m_h;
		m_h = NULL;
		return hTemp;
	}
 
	bool Create()
	{
		_ASSERTE(m_h == NULL);
		_ASSERTE(m_hType != -1);
		
		g_rt = SQLAllocHandle(THandle, NULL, &m_h);
		_ASSERTE(SQL_SUCCEEDED(g_rt));
		if (SQL_SUCCEEDED(g_rt) == FALSE)
			return FALSE;
		
		return TRUE;
	}
 
	void Destroy()
	{
		_ASSERTE(m_h != NULL);
		_ASSERTE(m_hType != -1);
		
		g_rt = SQLFreeHandle(THandle, m_h);
		_ASSERTE(SQL_SUCCEEDED(g_rt));
 
		m_h = NULL;
		m_hType = -1;
	}
 
	// TODO : test setting multiple attributes
	bool SetAttribute(_In_ SQLINTEGER attribute, _In_ SQLPOINTER value)
	{
		_ASSERTE(m_h != NULL);
 
		return static_cast<TDerived*>(this)->_SetAttribute(attribute, value);
	}
 
	// TODO : test getting multiple attributes
	bool GetAttribute(_In_ SQLINTEGER attribute, _Inout_ SQLPOINTER pValue, _Inout_ SQLINTEGER* pcbWritten)
	{
		_ASSERTE(m_h != NULL);
 
		return static_cast<TDerived*>(this)->_GetAttribute(attribute, pValue, pcbWritten);
	}
 
	operator SQLHANDLE()
	{
		return m_h;
	}
 
};
 

 
class __declspec(novtable) CEnviromentHandle : 
	public CHandle< CEnviromentHandle, SQL_HANDLE_ENV>
{
public:
 

	bool _SetAttribute(_In_ SQLINTEGER attribute, _In_ SQLPOINTER value)
	{
		_ASSERTE(m_h != NULL);
 
		g_rt = SQLSetEnvAttr(m_h, attribute, value, SQL_NTS);
		_ASSERTE(SQL_SUCCEEDED(g_rt));
		if (SQL_SUCCEEDED(g_rt) == FALSE)
			return FALSE;
		
		return TRUE;
	}
 
	// TODO : i might need last parameter. For now ignoreing
	bool _GetAttribute(_In_ SQLINTEGER attribute, _Inout_ SQLPOINTER pValue, _Inout_ SQLINTEGER* pcbWritten)
	{
		_ASSERTE(m_h != NULL);
 
		g_rt = SQLGetEnvAttr(m_h, attribute, pValue, SQL_IS_UINTEGER, pcbWritten);
		_ASSERTE(SQL_SUCCEEDED(g_rt));
		if (SQL_SUCCEEDED(g_rt) == FALSE)
			return FALSE;
		
		return TRUE;
	}
};
 
class __declspec(novtable) CConnectionHandle : 
	public CHandle< CConnectionHandle, SQL_HANDLE_DBC>
{
public:
 
	bool _SetAttribute(_In_ SQLINTEGER attribute, _In_ SQLPOINTER value)
	{
		_ASSERTE(m_h != NULL);
 
		g_rt = SQLSetConnectAttr(m_h, attribute, value, SQL_NTS);
		_ASSERTE(SQL_SUCCEEDED(g_rt));
		if (SQL_SUCCEEDED(g_rt) == FALSE)
			return FALSE;
		
		return TRUE;
	}
 
	// TODO : i might need last parameter. For now ignoreing
	bool _GetAttribute(_In_ SQLINTEGER attribute, _Inout_ SQLPOINTER pValue, _Inout_ SQLINTEGER* pcbWritten)
	{
		_ASSERTE(m_h != NULL);
 
		g_rt = SQLGetConnectAttr(m_h, attribute, pValue, SQL_IS_UINTEGER, pcbWritten);
		_ASSERTE(SQL_SUCCEEDED(g_rt));
		if (SQL_SUCCEEDED(g_rt) == FALSE)
			return FALSE;
		
		return TRUE;
	}
};
 

class __declspec(novtable) CStatementHandle : 
	public CHandle< CStatementHandle, SQL_HANDLE_STMT>
{
public:
 
	bool _SetAttribute(_In_ SQLINTEGER attribute, _In_ SQLPOINTER value)
	{
		_ASSERTE(m_h != NULL);
 
		g_rt = SQLSetStmtAttr(m_h, attribute, value, SQL_NTS);
		_ASSERTE(SQL_SUCCEEDED(g_rt));
		if (SQL_SUCCEEDED(g_rt) == FALSE)
			return FALSE;
		
		return TRUE;
	}
 
	// TODO : i might need last parameter. For now ignoreing
	bool _GetAttribute(_In_ SQLINTEGER attribute, _Inout_ SQLPOINTER pValue, _Inout_ SQLINTEGER* pcbWritten)
	{
		_ASSERTE(m_h != NULL);
 
		g_rt = SQLGetStmtAttr(m_h, attribute, pValue, SQL_IS_UINTEGER, pcbWritten);
		_ASSERTE(SQL_SUCCEEDED(g_rt));
		if (SQL_SUCCEEDED(g_rt) == FALSE)
			return FALSE;
		
		return TRUE;
	}
};
Posted 2-Aug-12 16:40pm
v3nOm_413
Edited 2-Aug-12 23:48pm
Malli_S25.8K
v2
Comments
Kenneth Haugland at 2-Aug-12 23:09pm
   
What Im I A Compiler? USe Visual studio insted :)
v3nOm_ at 2-Aug-12 23:20pm
   
what? i do use MSVC++ 2012
Kenneth Haugland at 2-Aug-12 23:30pm
   
I understood that, but what is the problem? Do you want us to *proof read* your code?
v3nOm_ at 3-Aug-12 1:43am
   
no....i'm wanting to get design advice/suggestions compared to what i have in place. i'm not asking why it wont compile...it compiles fine. I'm wanting to become a better programmer and therefore am looking for suggestions for improvement and opinions.
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

As suggestions. If you return bool then you have to return false/true instead of FALSE/TRUE, because you are not using BOOL. Second, don't name the class Handle. Instead of CConnectionHandle use CConnection name, or even better CDatabase. Instead ir CStatementHandle use CStatement or CQuery, and so on. And the best is to not expose the handle with HANDLE operator. Detach function is useless. Attach inside constructor is even more useless.
You have to follow ODBC strategic. For instance, when you make a CStatement, it makes sense with a CConnection. A CParameter makes sense only with a CStatement. CColumn makes sence only with CStatement, and so on.
I don't see any ODBC logics there.
Following ODBC logic, CConnection must have function Connect/DriverConnect/ConnectDirect/Disconnect or Open/Close, with DSN or with connection string. CStatement need to have such functions as Exec/ExecDirect, Fetch/Next/Prev/Close/Cancel/Bind. And navigating through columns, need to know result column count, row count, end and finish of result while fetching, errors in case of failing execution, so on.
 
This code is mostly dead. I don't see how you can use it to connect to a database, execute a query, get the result. But this is exactly why ODBC exists.
  Permalink  
v2
Comments
Volynsky Alex at 8-Aug-12 17:15pm
   
+5!
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 3

My advice is to test the code yourself first, to see if it solves the problem you are addressing.
 
I've had little need in the last decade, to do much with the ODBC layer. Using Wizard generated code such as MFC generated classes based on CRecordset, save a lot of time, and perform well enough for most operations.
 
I don't think I've done any extensive work with it since WFW 3.11 was king.
 
I'm sure there are applications in the wild that depend on the core ODBC calls for mission critical reasons, but they are very rare. I don't recommend you spend a lot of time learning it unless someone is paying you to do it.
  Permalink  
Comments
Volynsky Alex at 8-Aug-12 17:15pm
   
+5
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

I do appreciate your feedback and understand I am missing a lot Smile | :) I think it's better to get advice early then to late and have a lot of rewriting Smile | :) thanks for the advice and your time
  Permalink  
Comments
André Kraak at 3-Aug-12 14:27pm
   
If you have a question about or comment on a given solution use the "Have a Question or Comment?" option beneath the solution. When using this option the person who gave the solution gets an e-mail message and knows you placed a comment and can respond if he/she wants.
 
Please move the content of this solution to the solution you are commenting on and remove the solution.
Thank you.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
0 DamithSL 265
1 CPallini 235
2 OriginalGriff 233
3 Maciej Los 175
4 George Jonsson 170
0 OriginalGriff 5,305
1 DamithSL 4,382
2 Maciej Los 3,760
3 Kornfeld Eliyahu Peter 3,470
4 Sergey Alexandrovich Kryukov 2,901


Advertise | Privacy | Mobile
Web02 | 2.8.141216.1 | Last Updated 5 Aug 2012
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100