Original Post
In order to further increase my knowledge of ODBC and C++ good design practices i have decided to try my go at creating wrapper classes of the current ODBC C Api located on MSDN. I'm mainly wanting criticism on design problems people might see. Any advice is greatly appreciated ;) cheers
In order to avoid VTABLE overhead i have tried my best to implement simulated dynamic binding/CRTP ( which i believe i have implemented correctly )
In order to avoid VTABLE overhead i have tried my best to implement simulated dynamic binding/CRTP ( which i believe i have implemented correctly )
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;
}
};