C/C ++ ODBC处理包装 [英] C/C++ ODBC Handle Wrappers

查看:57
本文介绍了C/C ++ ODBC处理包装的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了进一步探索ODBC并提高我的编程经验,我打算将自己的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 :) 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;
	}
};

推荐答案

建议.如果返回布尔值,则必须返回false/true而不是FALSE/TRUE,因为您没有使用BOOL.第二,不要给Handle类命名.代替CConnectionHandle使用CConnection名称,甚至更好的CDatabase.相反,ir CStatementHandle使用CStatement或CQuery,依此类推.最好不要用HANDLE运算符暴露句柄.分离功能是没有用的.在构造函数内部附加甚至更无用.
您必须遵循ODBC策略.例如,当您创建一个CStatement时,使用CConnection才有意义. CParameter仅对CStatement有意义. CColumn仅使用CStatement来表示,等等.
我在那里看不到任何ODBC逻辑.
遵循ODBC逻辑,CConnection必须具有带有DSN或带有连接字符串的功能Connect/DriverConnect/ConnectDirect/Disconnect或Open/Close. CStatement需要具有Exec/ExecDirect,Fetch/Next/Prev/Close/Cancel/Bind等功能.在各列之间导航时,需要知道结果列数,行数,提取时结果的结束和结束,执行失败的情况下的错误等.

此代码已失效.我看不到如何使用它来连接数据库,执行查询和获取结果.但这正是ODBC存在的原因.
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.


我的建议是先自己测试代码,看看它是否可以解决您要解决的问题.

在过去的十年中,我几乎不需要使用ODBC层.使用向导生成的代码(例如MFC基于CRecordset生成的类),可以节省大量时间,并且对于大多数操作而言表现良好.

自从WFW 3.11成为国王以来,我认为我并没有对其进行任何广泛的工作.

我敢肯定,出于关键任务的原因,有些应用程序依赖于核心ODBC调用,但是它们很少见.我不建议您花很多时间来学习它,除非有人付钱给您做它.
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.


我很感谢您的反馈,并理解我很想念:)我认为最好早点得到建议,然后再迟到并进行大量重写:)感谢您的建议和您的时间
I do appreciate your feedback and understand I am missing a lot :) I think it''s better to get advice early then to late and have a lot of rewriting :) thanks for the advice and your time


这篇关于C/C ++ ODBC处理包装的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆