`
dyx1024
  • 浏览: 114795 次
  • 性别: Icon_minigender_1
  • 来自: 西安
文章分类
社区版块
存档分类
最新评论

一个非常灵活的ODBC编程方法

 
阅读更多

通常我们在用VC进行数据库编程时首先会考虑到用向导通过ADO控件操作.的确,这是一个非常方便的方法.但也存在很大的不足,编程上的一些限制暂且不提,在客户使用方面,如你把用ADO控件写成的程序移动到另一台机器,由于相应的控件可能并没有提前安装,还有路径等问题.使得使用起来极为不便,本文提供了一个封装好的ODBC类,很好地解决了这个问题,实现很灵活的编程.我通过自己创建的一个示例程序说明:

1. 我封装SQL的操作封装成一个类,用户使用时只要调用就行.

//tool.h

#include <sql.h>

#include <sqlext.h>

#include <odbcss.h>

#include <odbcinst.h>

#define SQLERR_FORMAT "SQL Error State:%s, Native Error Code: %lX, ODBC Error: %s"

#define MM_MAX_DB_ERRMSG_SIZE 1024

typedef struct tagHIS_ADMIN //示例程序所用结构

{

int iId;

char strName[64];

char strPwd[64];

char strRemark[256];

}HIS_ADMIN, *LPHIS_ADMIN;

BOOL InitSQLEnvironment(SQLHANDLE *pEnv);

BOOL CreateDBConnect(SQLHDBC *phDBC, SQLHANDLE dbEnv, const char* pOdbcName,

const char* pUserName, const char* pPwd, char *errmsg);

BOOL GetDBError(SQLCHAR *errmsg, SWORD fHandleType, SQLHANDLE handle);

BOOL CreateDBState(SQLHSTMT *phStMt, SQLHDBC hDBC, char *errmsg);

//tool.cpp

注意在头部包含此语句:

#pragma comment(lib, "odbc32.lib")

//初始化.

BOOL InitSQLEnvironment(SQLHANDLE *pEnv)

{

// Allocate an Environment Handle

if (SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, pEnv) != SQL_SUCCESS)

{

return FALSE;

}

SQLRETURN sRet = SQLSetEnvAttr(*pEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER);

if (sRet != SQL_SUCCESS)

{

SQLFreeHandle(SQL_HANDLE_ENV, *pEnv);

return FALSE;

}

return TRUE;

}

//创建数据库连接

BOOL CreateDBConnect(SQLHDBC *phDBC, SQLHANDLE dbEnv, const char* pOdbcName,

const char* pUserName, const char* pPwd, char *errmsg)

{

// Allocate ODBC connection handle and connect.

SQLRETURN sRet;

sRet = SQLAllocHandle(SQL_HANDLE_DBC, dbEnv, phDBC);

if((sRet != SQL_SUCCESS_WITH_INFO) && (sRet != SQL_SUCCESS))

{

GetDBError((SQLCHAR *)errmsg, SQL_HANDLE_DBC, NULL);

return FALSE;

}

sRet = SQLConnect(*phDBC, (UCHAR *)pOdbcName, SQL_NTS,

(UCHAR *)pUserName, SQL_NTS,

(UCHAR *)pPwd, SQL_NTS);

if((sRet != SQL_SUCCESS) && (sRet != SQL_SUCCESS_WITH_INFO))

{

GetDBError((SQLCHAR *)errmsg, SQL_HANDLE_DBC, *phDBC);

SQLFreeHandle(SQL_HANDLE_DBC, *phDBC);

*phDBC = SQL_NULL_HDBC;

return FALSE;

}

return TRUE;

}

//自定义错误函数

BOOL GetDBError(SQLCHAR *errmsg, SWORD fHandleType, SQLHANDLE handle)

{

UCHAR szErrState[SQL_SQLSTATE_SIZE + 1]; // SQL Error State string

UCHAR szErrText[SQL_MAX_MESSAGE_LENGTH + 1]; // SQL Error Text string

char szBuffer[SQL_SQLSTATE_SIZE + SQL_MAX_MESSAGE_LENGTH + 1];

// formatted Error text Buffer

SWORD wErrMsgLen; // Error message length

SQLINTEGER iErrCode; // Native Error code

int iSize; // Display Error Text size

SQLRETURN nErrResult; // Return Code from SQLGetDiagRec

SWORD sMsgNum = 1;

BOOL bRetVal = TRUE;

szBuffer[0] = '/0';

while((nErrResult = SQLGetDiagRec(fHandleType, handle, sMsgNum++, szErrState, &iErrCode, szErrText,

SQL_MAX_MESSAGE_LENGTH - 1, &wErrMsgLen)) != SQL_NO_DATA)

{

if(nErrResult == SQL_ERROR || nErrResult == SQL_INVALID_HANDLE)

{

break;

}

wsprintf(szBuffer, SQLERR_FORMAT, (LPSTR)szErrState, iErrCode, (LPSTR)szErrText);

if (strncmp((char *)szErrState, "08", 2) == 0 || strncmp((char *)szErrState, "01000", 5) == 0)

{

//数据库已经断开

bRetVal = FALSE;

}

iSize = strlen((char *)errmsg);

if (iSize && (iSize + strlen(szBuffer) + 1) >= MM_MAX_DB_ERRMSG_SIZE)

{

break;

}

if (iSize)

{

strcat((char *)errmsg, "/n");

}

strcat((char *)errmsg, szBuffer);

}

return bRetVal;

}

//执行函数

BOOL CreateDBState(SQLHSTMT *phStMt, SQLHDBC hDBC, char *errmsg)

{

// Allocate statement handle, then execute command.

SQLRETURN sRet;

sRet = SQLAllocHandle(SQL_HANDLE_STMT, hDBC, phStMt);

if((sRet != SQL_SUCCESS) && (sRet != SQL_SUCCESS_WITH_INFO))

{

GetDBError((SQLCHAR *)errmsg, SQL_HANDLE_STMT, NULL);

return FALSE;

}

return TRUE;

}

2.实际使用方法:

在His.cpp中

BOOL CHisApp::InitInstance()

{

///////////////////////begin///////////////////////////////////////

if (!InitSQLEnvironment(&m_hDBEnv))

{

AfxMessageBox("设置ODBC环境失败");

return FALSE;

}

char errmsg1[512];

BOOL bRetVal = TRUE;

memset(errmsg1, 0, sizeof(errmsg1));

// his_conn为数据源名,hisuser:用户名,888888:密码

bRetVal = CreateDBConnect(&m_hDBC, m_hDBEnv, "his_conn", "hisuser", "888888", errmsg1);

if(!bRetVal)

{

AfxMessageBox(errmsg1);

return FALSE;

}

bRetVal = CreateDBState(&m_hStMt, m_hDBC, errmsg1);

if(!bRetVal)

{

AfxMessageBox(errmsg1);

return FALSE;

}

///////////////////////end///////////////////////////////////////

AfxEnableControlContainer();

// Standard initialization

// If you are not using these features and wish to reduce the size

// of your final executable, you should remove from the following

// the specific initialization routines you do not need.

#ifdef _AFXDLL

Enable3dControls(); // Call this when using MFC in a shared DLL

#else

Enable3dControlsStatic(); // Call this when linking to MFC statically

#endif

// Change the registry key under which our settings are stored.

// TODO: You should modify this string to be something appropriate

// such as the name of your company or organization.

SetRegistryKey(_T("Local AppWizard-Generated Applications"));

LoadStdProfileSettings(); // Load standard INI file options (including MRU)

// Register the application's document templates. Document templates

// serve as the connection between documents, frame windows and views.

CSingleDocTemplate* pDocTemplate;

pDocTemplate = new CSingleDocTemplate(

IDR_MAINFRAME,

RUNTIME_CLASS(CHisDoc),

RUNTIME_CLASS(CMainFrame), // main SDI frame window

RUNTIME_CLASS(CHisView));

AddDocTemplate(pDocTemplate);

// Parse command line for standard shell commands, DDE, file open

CCommandLineInfo cmdInfo;

ParseCommandLine(cmdInfo);

// Dispatch commands specified on the command line

if (!ProcessShellCommand(cmdInfo))

return FALSE;

// The one and only window has been initialized, so show and update it.

m_pMainWnd->ShowWindow(SW_SHOW);

m_pMainWnd->UpdateWindow();

return TRUE;

}

3.具体使用举例:

BOOL CRightListView::ReadRecord(CArray<HIS_ADMIN *, HIS_ADMIN*> *ur)

{

SQLRETURN sRet;

char errmsg[MM_MAX_DB_ERRMSG_SIZE];

char szState[512];

long reason;

SQLINTEGER len[12];

char szAction[1024];

sprintf(szAction, "管理员查询");

sprintf(szState, "exec his..his_proc_get_admin");//已经创建好的存储过程

sRet = SQLExecDirect(theApp.m_hStMt, (SQLCHAR *)szState, SQL_NTS);

if (sRet != SQL_SUCCESS && sRet != SQL_SUCCESS_WITH_INFO)

{

AfxMessageBox("执行查询语句失败");

return FALSE;

}

else

{

SQLBindCol(theApp.m_hStMt, 1, SQL_C_LONG, &reason, 0, &len[0]);

SQLBindCol(theApp.m_hStMt, 2, SQL_C_CHAR, errmsg, MM_MAX_DB_ERRMSG_SIZE, &len[1]);

sRet = SQLFetch(theApp.m_hStMt);

if (sRet != SQL_SUCCESS && sRet != SQL_SUCCESS_WITH_INFO)

{

AfxMessageBox("没有结果");

return FALSE;

}

sRet = SQLMoreResults(theApp.m_hStMt);

if (sRet != SQL_SUCCESS && sRet != SQL_SUCCESS_WITH_INFO)

{

AfxMessageBox("failed");

return FALSE;

}

HIS_ADMIN dat;

HIS_ADMIN *pData;

SQLBindCol(theApp.m_hStMt, 1, SQL_C_LONG, &dat.iId, 0, &len[0]);

SQLBindCol(theApp.m_hStMt, 2, SQL_C_CHAR, &dat.strName, 64, &len[1]);

SQLBindCol(theApp.m_hStMt, 3, SQL_C_CHAR, &dat.strPwd, 64, &len[2]);

SQLBindCol(theApp.m_hStMt, 4, SQL_C_CHAR, &dat.strRemark, 255, &len[3]);

while(1)

{

memset(&dat, 0, sizeof(HIS_ADMIN));

sRet = SQLFetch(theApp.m_hStMt);

if (sRet != SQL_SUCCESS && sRet != SQL_SUCCESS_WITH_INFO)

{

break;

}

pData = (HIS_ADMIN *)calloc(1, sizeof(HIS_ADMIN));

VERIFY(pData);

memcpy(pData, &dat, sizeof(HIS_ADMIN));

ur->Add(pData); //save recordset

}

}

return TRUE;

}

分享到:
评论

相关推荐

    Oracle SQL高级编程(资深Oracle专家力作,OakTable团队推荐)--随书源代码

    他认为对于SQL的学习是永无止境的,相信每一个查询Oracle数据库的人都需要精通SQL语言,才能写出高效的查询。他参与本书的编写就是为了帮助别人实现这一目标。 目录 封面 -11 封底 -10 扉页 -9 版权 -8 版权声明 -7...

    非Access数据库在VB中的编程及应用

    从VB的程序代码的角度来看,ODBC,ISAM驱动程序以及Ms Access数据库的整个外部结构够可以统一为一个一致的编程接口。也即是说,提供给VB应用程序员的记录集对象视图同所使用的数据库格式及类型是相互独立的。即对...

    VB中调用带参数存储过程

    ---- 我们知道,VB的数据库编程有许多种方法,比如直接用ODBC API编程,这种方法灵活、高效,程序员可以实现对数据库复杂的控制;也可以用VB中的数据对象,如RDO(远程数据对象)、DAO(数据访问对象)、ADO...

    C#编程经验技巧宝典

    72 &lt;br&gt;0102 将字符串首字母转换大写 72 &lt;br&gt;0103 如何进行字节数组和字符串的相互转换 72 &lt;br&gt;0104 如何把一个按空格分割的字符串存储在一个ArrayList数组中 73 &lt;br&gt;4.2 获取字符串信息 73 ...

    Java入门1·2·3:一个老鸟的Java学习心得.PART3(共3个)

    10.2.3 记得给类一个无参数的构造方法 255 10.2.4 调用父类中的构造方法 256 10.2.5 对象也会“变脸” 258 10.2.6 遵守语法,正确“变脸” 262 10.3 覆盖——与继承如影随形 264 10.3.1 当方法不再通用 264 ...

    ASP的Internet/Intranet编程常见问题

    基于ASP技术开发Internet/Intranet上的MIS系统是非常方便的,首先是它借用了ADO技术和概念,同时通过ODBC访问数据库,达到了充分的灵活性和多平台性,另外,由于ASP利用VBS和JS脚本语言,也保证大多数开发者很快进入...

    JAVA入门1.2.3:一个老鸟的JAVA学习心得 PART1(共3个)

    10.2.3 记得给类一个无参数的构造方法 255 10.2.4 调用父类中的构造方法 256 10.2.5 对象也会“变脸” 258 10.2.6 遵守语法,正确“变脸” 262 10.3 覆盖——与继承如影随形 264 10.3.1 当方法不再通用 264 ...

    Python Cookbook

    15.1 实现一个XML-RPC方法调用 536 15.2 服务XML-RPC请求 537 15.3 在Medusa中使用XML-RPC 539 15.4 允许XML-RPC服务被远程终止 541 15.5 SimpleXMLRPCServer的一些细节 542 15.6 给一个XML-RPC服务提供一个...

    vc++ 应用源码包_6

    非常好的一个实例,把网络连接的UDP/TCP都插入到CList控件中显示出来。 VC++视频捕捉系统 win32下 视频操作。 VC++视频会议系统(完整)有开发文档。使用了系统自带的视频。 Windows核心编程(第五版)随书源代码 ...

    vc++ 应用源码包_1

    非常好的一个实例,把网络连接的UDP/TCP都插入到CList控件中显示出来。 VC++视频捕捉系统 win32下 视频操作。 VC++视频会议系统(完整)有开发文档。使用了系统自带的视频。 Windows核心编程(第五版)随书源代码 ...

    vc++ 应用源码包_3

    非常好的一个实例,把网络连接的UDP/TCP都插入到CList控件中显示出来。 VC++视频捕捉系统 win32下 视频操作。 VC++视频会议系统(完整)有开发文档。使用了系统自带的视频。 Windows核心编程(第五版)随书源代码 ...

    vc++ 应用源码包_5

    非常好的一个实例,把网络连接的UDP/TCP都插入到CList控件中显示出来。 VC++视频捕捉系统 win32下 视频操作。 VC++视频会议系统(完整)有开发文档。使用了系统自带的视频。 Windows核心编程(第五版)随书源代码 ...

    vc++ 应用源码包_2

    非常好的一个实例,把网络连接的UDP/TCP都插入到CList控件中显示出来。 VC++视频捕捉系统 win32下 视频操作。 VC++视频会议系统(完整)有开发文档。使用了系统自带的视频。 Windows核心编程(第五版)随书源代码 ...

    JAVA上百实例源码以及开源项目

    6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用...

    JAVA上百实例源码以及开源项目源代码

    6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用...

    DAO的几个小的使用

    数据访问对象(DAO) 使用Microsoft Jet数据库引擎,可访问Microsoft Access 数据库,ODBC数据源,以及其他可安装的ISAM数据库。在VC平台上有灵活的DAO编程方法。MFC将DAO类封装其中。

    高等学校教材管理系统的设计与实现_

    第1节 系统开发的意义 教材管理对各个学校而言,都是一项复杂、烦琐的工作, 是高校教务管理中...在其他语言中需要一大段程序实现的功能只需要一个SQL语句就可以达到目的,这也意味着用SQL语言可以写出非常复杂的语句。

    vc++ 开发实例源码包

    演示了OpenG的使用方法,内含几个实例,一个实例就3个文件。 p2p vb实例。 p2p+technology 文档。 P2P视频技术源码(含开发文档) 目前的协议有如下一些特点: 1) 客户向服务器发送请求, 每个请求的长度不定. 请求...

Global site tag (gtag.js) - Google Analytics