分享
 
 
 

利用VC++获取异构型数据库库结构信息

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

利用VC++获取异构型数据库库结构信息

空军电讯工程学院计算机室 万映辉 邸晓奕

摘 要:本文在介绍ODBC技术的基础上,将MFC和ODBC API结合起来创建了两个自定义 类,

实现了对任意异构型数据库库结构信息的获取。

关键字:ODBC,MFC,异构型数据库,记录集

一. 问题的提出

随着数据库技术在各个应用领域的迅速发展,市场上推出了多种数据库系统,为了充分利用资源,实现信息共享,以便用户能对异构型数据库实现透明的访问(包括数据查询、更新和交换等功能),作者开发了异构型数据库通信平台。在平台的研制过程中,获取各种异构型数据库的结构信息是进行数据访问的前提。作者以VC++5.0为开发语言,利用ODBC实现了这一关键技术。

二. ODBC技术介绍

ODBC技术是指开放性数据库连接技术,该技术使应用程序无需关心数据源来自何种DBMS,利用其标准接口实现与数据源之间的数据交换。传统的ODBC编程是利用高级语言(如C语言)调用ODBC的API来实现。应用程序要求驱动程序管理器和每个驱动程序为ODBC环境、每个连接以及每个SQL语句分配信息存储空间,并返回指向各个存储区的句柄供其调用。ODBC接口定义了三种句柄类型:

环境句柄:为全程信息标识内存存储,包括有效连接句柄及当前活动连接句柄。ODBC将环境句柄定义为HENV类型的变量。应用程序使用单一环境句柄,它必须在连接到数据源前请求该句柄。

连接句柄:为特定连接的信息标识了内存存储。ODBC将连接句柄定义为HDBC类型。应用程序必须在连接到数据源前请求连接句柄。每个连接句柄与环境句柄有关。然而,环境句柄可以有多个与其有关的连接句柄。

语句句柄:为SQL语句信息标识内存存储。ODBC将语句句柄定义为HSTMT类型变量。应用程序必须在提交SQL请求之前请求语句句柄。每个语句句柄与一个连接句柄有关。然而,每个连接句柄可以有多个与其相关的语句句柄。

下面以C语言为例说明传统ODBC编程的一般过程。

1、 环境申请,分配环境句柄

HENV henv;

SQLAllocEnv(&henv);

说明:分配一个环境句柄,支持一个或多个数据源连接。

2、 连接申请,分配连接句柄

HDBC hdbc;

SQLAllocConnect(henv,&hdbc);

说明:一个连接句柄对应一个数据源,可以有多个连接句柄。

3、 连接数据源,用连接句柄连接到数据源

SQLDriverConnect(hdbc,...);

说明:以对话框方式获取注册信息,并连接数据源。

4、 语句申请,分配语句句柄

SQLAllocStmt(hdbc,&hstmt);

说明:获得语句句柄,以便执行SQL语句。

5、 执行SQL语句

SQLExecDirect(hstmt,SQLStatement,..);

说明:利用语句句柄,执行SQL语句。

6、 释放所有资源

SQLfreeStemt(hstmst,...); //释放语句句柄

SQLDisconnect(hdbc); //断开连接

SQLFreeConnect(hdbc); //释放当前数据库连接句柄

SQLFreeEnv(henv); //释放环境句柄

三. 利用VC++和ODBC技术获取异构型数据库结构信息

传统的ODBC编程过程比较复杂,各种参数不易理解,且直接获取返回的数据较困难。VC++ 5.0的MFC类库对ODBC的API进行封装,部分简化了ODBC编程(尤其是对数据库记录集的操作),但单纯利用MFC类获取异构型数据库的结构信息仍然比较困难,因此需要将MFC和传统ODBC API编程结合起来。作者利用ODBC接口函数重载了MFC中CRecordset类的部分成员函数,创建CTable和CColumns类。利用这两个新创建的类,可以很方便的获取异构型数据库结构信息。

下面就是关于CTable和Ccolumns类的定义:

class CTable : public CRecordset

{

virtual CString GetDefaultConnect() { return ""; }

virtual CString GetDefaultSQL() { return ""; }

public:

CTable(CDatabase* pDatabase);

BOOL Open(LPCSTR pszTableQualifier = NULL,

LPCSTR pszTableOwner = NULL,

LPCSTR pszTableName = NULL,

LPCSTR pszTableType = NULL,

UINT nOpenType = forwardOnly);

CString m_strTableQualifier;

CString m_strTableOwner;

CString m_strTableName;

CString m_strTableType;

CString m_strRemarks;

virtual void DoFieldExchange(CFieldExchange*);

};

class CColumns : public CRecordset

{

virtual CString GetDefaultConnect() { return ""; }

virtual CString GetDefaultSQL() { return ""; }

public:

CColumns(CDatabase* pDatabase);

BOOL Open(LPCSTR pszTableQualifier = NULL,

LPCSTR pszTableOwner = NULL,

LPCSTR pszTableName = NULL,

LPCSTR pszColumnName = NULL,

UINT nOpenType = forwardOnly);

CString m_strTableQualifier;

CString m_strTableOwner;

CString m_strTableName;

CString m_strColumnName;

int m_nDataType;

CString m_strTypeName;

long m_nPrecision;

long m_nLength;

int m_nScale;

int m_nRadix;

int m_fNullable;

CString m_strRemarks;

virtual void DoFieldExchange(CFieldExchange*);

};

BOOL CColumns::Open(LPCSTR pszTableQualifier,

LPCSTR pszTableOwner,LPCSTR pszTableName,LPCSTR pszColumnName,

UINT nOpenType)

{

RETCODE nRetCode;

UWORD bFunctionExists;

//检验是否支持SQLColumns函数

AFX_SQL_SYNC(::SQLGetFunctions(m_pDatabase->m_hdbc,

SQL_API_SQLCOLUMNS,&bFunctionExists));

if (!Check(nRetCode) || !bFunctionExists)

{

if (!bFunctionExists)

TRACE(_T("SQLColumns 不支持\n"));

return FALSE;

}

//设置缓冲区状态,分配语句句柄

SetState(nOpenType,NULL,readOnly);

if (!AllocHstmt())

return FALSE;

TRY

{

OnSetOptions(m_hstmt);

AllocStatusArrays();

// 调用ODBC的SQLColumns函数

AFX_ODBC_CALL(::SQLColumns(m_hstmt,

(UCHAR FAR*)pszTableQualifier,SQL_NTS,

(UCHAR FAR*)pszTableOwner,SQL_NTS,

(UCHAR FAR*)pszTableName,SQL_NTS,

(UCHAR FAR*)pszColumnName,SQL_NTS));

if (!Check(nRetCode))

ThrowDBException(nRetCode,m_hstmt);

// 分配内存,填写信息

AllocAndCacheFieldInfo();

AllocRowset();

MoveNext();

m_bBOF = m_bEOF;

}

//异常信息的捕获

CATCH_ALL(e)

{

Close();

THROW_LAST();

}

END_CATCH_ALL

return TRUE;

}

//获取记录集信息

void CColumns::DoFieldExchange(CFieldExchange* pFX)

{

pFX->SetFieldType(CFieldExchange::outputColumn);

RFX_Text(pFX,_T("TABLE_QUALIFIER"),m_strTableQualifier);

RFX_Text(pFX,_T("TABLE_OWNER"),m_strTableOwner);

RFX_Text(pFX,_T("TABLE_NAME"),m_strTableName);

RFX_Text(pFX,_T("COLUMN_NAME"),m_strColumnName);

RFX_Int(pFX,_T("DATA_TYPE"),m_nDataType);

RFX_Text(pFX,_T("TYPE_NAME"),m_strTypeName);

RFX_Long(pFX,_T("PRECISION"),m_nPrecision);

RFX_Long(pFX,_T("LENGTH"),m_nLength);

RFX_Int(pFX,_T("SCALE"),m_nScale);

RFX_Int(pFX,_T("RADIX"),m_nRadix);

RFX_Int(pFX,_T("NULLABLE"),m_fNullable);

RFX_Text(pFX,_T("REMARKS"),m_strRemarks);

}

CColumns::CColumns(CDatabase* pDatabase): CRecordset(pDatabase)

{

m_strTableQualifier = _T("");

m_strTableOwner = _T("");

m_strTableName = _T("");

m_strColumnName = _T("");

m_nDataType = 0;

m_strTypeName = _T("");

m_nPrecision = 0;

m_nLength = 0;

m_nScale = 0;

m_nRadix = 0;

m_fNullable = 0;

m_strRemarks = _T("");

m_nFields = 12;

}

CTable::CTable(CDatabase* pDatabase): CRecordset(pDatabase)

{

m_strTableQualifier = _T("");

m_strTableOwner = _T("");

m_strTableName = _T("");

m_strTableType = _T("");

m_strRemarks = _T("");

m_nFields = 5;

}

BOOL CTable::Open(LPCSTR pszTableQualifier,

LPCSTR pszTableOwner,LPCSTR pszTableName,LPCSTR pszTableType,

UINT nOpenType)

{

RETCODE nRetCode;

UWORD bFunctionExists;

//检验是否支持SQLTables 函数

AFX_SQL_SYNC(::SQLGetFunctions(m_pDatabase->m_hdbc,

SQL_API_SQLTABLES,&bFunctionExists));

if (!Check(nRetCode) || !bFunctionExists)

{

if (!bFunctionExists)

TRACE(_T("SQLTables 不支持\n"));

return FALSE;

}

//设置缓冲区状态,分配语句句柄

SetState(nOpenType,NULL,readOnly);

if (!AllocHstmt())

return FALSE;

TRY

{

OnSetOptions(m_hstmt);

AllocStatusArrays();

//调用 ODBC的SQLTables函数

AFX_ODBC_CALL(::SQLTables(m_hstmt,

(UCHAR FAR*)pszTableQualifier,SQL_NTS,

(UCHAR FAR*)pszTableOwner,SQL_NTS,

(UCHAR FAR*)pszTableName,SQL_NTS,

(UCHAR FAR*)pszTableType,SQL_NTS));

if (!Check(nRetCode))

ThrowDBException(nRetCode,m_hstmt);

// 分配内存,填写信息

AllocAndCacheFieldInfo();

AllocRowset();

MoveNext();

m_bBOF = m_bEOF;

}

//异常信息的捕获

CATCH_ALL(e)

{

Close();

THROW_LAST();

}

END_CATCH_ALL

return TRUE;

}

void CTable::DoFieldExchange(CFieldExchange* pFX)

{

pFX->SetFieldType(CFieldExchange::outputColumn);

RFX_Text(pFX,_T("TABLE_QUALIFIER"),m_strTableQualifier);

RFX_Text(pFX,_T("TABLE_OWNER"),m_strTableOwner);

RFX_Text(pFX,_T("TABLE_NAME"),m_strTableName);

RFX_Text(pFX,_T("TABLE_TYPE"),m_strTableType);

RFX_Text(pFX,_T("REMARKS"),m_strRemarks);

}

以上两个类对CRecordset的Open和DoFieldExchange函数进行了重载。应用程序可以在需要时创建CTable或Ccolumns类,并调用OPEN成员函数建立相应的表结构和字段结构记录集。接下来就可以通过下列函数来遍历异构型数据库的结构信息了。

Void CRecordset::MoveFirst(); //移到第一条记录

Void CRecordset::MoveLast(); //移到最后一条记录

Void CRecordset::MovePrev(); //移到前一条记录

Void CRecordset::MoveNext(); //移到后一条记录

BOOL CRecordset::IsBOF(); //判断是否到达第一条记录前

BOOL CRecordset::IsEOF(); //判断是否到达最后一条记录后

四、结束语

利用自定义的CTable和Ccolumns类,应用程序能获取任何异构型数据库库结构信息。根据获得的信息可以方便的对未知数据库进行相应的操作。若将CTable和Ccolumns类与文档类、视类结合起来,就可以在窗口里以一定的方式显示结构信息。作者利用以上技术在异构型数据库通信平台上成功实现了对各种异构型数据库库结构信息的获取。

参考文献:

Mircosoft 《ODBC 2.0 Programmer's Reference and SDK Guide》

利用VC++获取异构型数据库库结构信息

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有