c++开发数据库

http://blog.csdn.net/smallbasket/article/details/4895551

几种VC++数据库开发技术的比较

从功能简单的数据库(如Jet Engine)到复杂的大型数据库系统(如oracle),VC++6.0都提供了一些编程接口。本文主要介绍以下五种:

  1.ODBC API;

  2.MFC ODBC类;

  3.MFC DAO类;(数据访问对象)

  4.MFC的OLE/DB;

  5.ActiveX数据对象(ADO)。

  1.开放数据库连接(ODBC API):提供了一个通用的编程接口,允许程序与多种不同的数据库连接。它为Oracle,SQL Server,MS Excel等都提供了驱动程序,使得用户可以使用SQL语句对数据库进行直接的底层功能操作。在使用ODBC API时,用户须引入的头文件为"sql.h","sqlext.h","sqltypes.h"。用ODBC API创建数据库应用程序遵循一定的基本步骤:

  第一步是分配ODBC环境,使一些内部结构初始化。完成这一步,须分配一个SQLHENV类型的变量在ODBC环境中做句柄使用。

  第二步是为将要使用的每一个数据源分配一个连接句柄,由函数SQLALLocHandle()完成。

  第三步是使用SQLConnect()把连接句柄与数据库连接,可以先通过SQLSetConnectAttr()设置连接属性。

  然后就可以进行SQL语句的操作,限于篇幅,相关的函数就不具体介绍了,读者可以参考相关书籍。

  操作完成后,用户取回相应的结果,就可以取消与数据库的连接。

  最后需要释放ODBC环境。

  ODBC API的特点是功能强大丰富,提供了异步操作,事务处理等高级功能,但相应的编程复杂,工作量大。

  2.MFC ODBC类:MFC1.5后的版本里引入封装了ODBC功能的类。通过这些类提供与ODBC的接口,使得用户可以不须处理ODBC API中的繁杂处理就可以进行数据库操作。主要的MFC ODBC类如下。

  CDatabase类:一个CDatabase对象表示一个到数据源的连接,通过它可以操作数据源。应用程序可使用多个CDatabase对象:构造一个对象并调用OpenEx()成员函数打开一个连接。接着构造CRecordSet对象以操作连接的数据源,并向CDatabase对象传递记录集构造程序指针。完成使用后用Close()成员函数销毁CDatabase对象。一般情况下并不需要直接使用CDatabase对象,因为CRecordSet对象可以实现大多数的功能。但是在进行事务处理时,CDatabase就起到关键作用。事务(Transaction)指的是将一系列对数据源的更新放在一起,同时提交或一个也不提交,为的是确保多用户对数据源同时操作时的数据正确性。

  CRecordSet类:一个CRecordSet对象代表一个从数据源选择的一组记录的集合-记录集。记录集有两种形式:snapshot和dynaset。前者表示数据的静态视图,后者表示记录集与其他用户对数据库的更新保持同步。通过CRecordSet对象,用户可以对数据库中的记录进行各种操作。

  CRecordView类:CRecordView对象是在空间中显示数据库记录的视图。这种视图是一种直接连到一个CRecordSet对象的格式视图,它从一个对话框模板资源创建,并将CRecordSet对象的字段显示在对话框模板的控件里。对象利用DDX和RFX机制,使格式上的控件和记录集的字段之间数据移动自动化,也就是说,用户甚至不要编写一行代码就可以实现简单的数据库记录查看程序。

  CDBException类:由Cexception类派生,以三个继承的成员变量反映对数据库操作时的异常:

   m_nRetCode:以ODBC返回代码(SQL_RETURN)的形式表明造成异常的原因。

   m_strError:字符串,描述造成抛出异常的错误原因。

   m_strStateNativeOrigin:字符串,用以描述以ODBC错误代码表示的异常错误。

  MFC数据库类成员函数都能抛出CDBException类型的异常,所以在代码对数据库进行操作后监测异常是正确做法。

  MFC ODBC类在实际开发中应用最广,因为它功能丰富,操作相对简便。

3.MFC DAO(数据访问对象)编程:DAO用于和微软的Access数据库接口。在数据库应用程序如果只需与Access数据库接口时,使用DAO编程较方便。其主要类如下。

  CDaoWorkspace:CDaoWorkspace对象可以让一个用户管理从登陆到离开期间,指定的密码保护的数据库会话全过程。大多数情况下不要多个工作区也不要创建明确的工作区对象。因为在打开数据库和记录集对象时,它们可以使用DAO缺省工作区。

  CDaoDatabase:代表一个连接,类似上述CDatabase类。

   CDaoRecordSet:用来选择记录集并操作,类似上述CRecordSet类。

   CDaoRecordView:类似上述CRecordView类。

   CDaoException:类似上述CDBException类。

   CDaoTableDef:表示基本表或附加表的定义。每个DAO数据库对象包括一个称为TableDef的收集,包含所有存储的DAO表定义对象。CDaoTableDef对象可以用来控制表定义。

   CDaoQueryDef:CDaoQueryDef对象表示了一个查询定义(querydef)。

   CDaoFieldExchange:支持数据库类使用的DAO字段交换(DFX)例程。也可处理事务,类似MFC ODBC类。

  MFC DAO仅用来支持Access数据库,应用范围相对固定。

  4.OLE DB:OLE DB在数据提供程序和用户之间提供了灵活的组件对象模型(COM)接口,这种灵活性有时会使得操作复杂化。OLE DB框架定义了应用的三个基本类。

  数据提供程序Data Provider:拥有自己的数据并以表格形式显示数据的应用程序。提供OLE DB的行集COM接口,期显示范围可以从单一数据表格的简单提供者知道更复杂的分布式数据库系统。

  使用者Consumers:使用OLE DB接口对存储在数据提供程序中的数据进行控制的应用程序。用户应用程序归为使用类。

  服务提供程序Service Provider:是数据提供程序和使用者的组合。服务提供程序没有自己的数据,但使用

  OLE DB使用者接口来访问存储在数据提供程序中的数据。然后,服务提供程序通过打开数据提供程序接口使得数据对使用者有效。服务提供程序常用于向应用程序提供高层次服务,比如高级分布式查询。

  OLE DB编程时,用户使用组件对象开发应用程序。这些组件有:

   枚举器:用于列出可用的数据源;

   数据源:代表单独的数据和服务提供程序,用于创建对话;

   对话:用于创建事务和命令;

   事务:用于将多个操作归并为单一事务处理;

   命令:用于向数据源发送文本命令(SQL),返回行集;

   错误:用于获得错误信息。

  5.ActiveX数据对象(ADO):是微软提供的面向对象的接口,与OLE DB类似,但接口更简单,具有更广泛的特征数组和更高程度的灵活性。ADO基于COM,提供编程语言可利用的对象,除了面向VC++,还提供面向其他各种开发工具的应用,如VB,VJ等。ADO在服务器应用方面非常有用,特别是对于动态服务器页面ASP(Active Server Page)。

  ADO对象结构类似于OLE DB,但并不依靠对象层次。大多数情况下,用户只需要创建并只使用需要处理的对象。下面的对象类组成了ADO接口。

   Connection:用于表示与数据库的连接,以及处理一些命令和事务。

   Command:用于处理传送给数据源的命令。

   Recordset:用于处理数据的表格集,包括获取和修改数据。

   Field:用于表示记录集中的列信息,包括列值和其他信息。

   Parameter:用于对传送给数据源的命令之间来回传送数据。

   Property:用与操作在ADO中使用的其他对象的详细属性。

   Error:用于获得可能发生的错误的详细信息。

  在VC++使用ADO需要进行COM操作,详细方法在此就不赘述了。

  在当今流行的分布式开发环境下,VC++6.0在数据库开发方面有较强的优势,学会

  在不同的场合选用不同的技术,对开发人员来说是必要的技术。


ODBC基本概念

ODBC(Open Database Connectivity,开放数据库互连)是微软公司开放服务结构(WOSA,Windows Open Services Architecture)中有关数据库的一个组成部分,它建立了一组规范,并提供了一组对数据库访问的标准API(应用程序编程接口)。这些API利用SQL来完成其大部分任务。ODBC本身也提供了对SQL语言的支持,用户可以直接将SQL语句送给ODBC。

  一个基于ODBC的应用程序对数据库的操作不依赖任何DBMS,不直接与DBMS打交道,所有的数据库操作由对应的DBMS的ODBC驱动程序完成。也就是说,不论是FoxPro、Access还是Oracle数据库,均可用ODBC API进行访问。由此可见,ODBC的最大优点是能以统一的方式处理所有的数据库。

  一个完整的ODBC由下列几个部件组成:

  应用程序(Application)。

  ODBC管理器(Administrator)。该程序位于Windows 95控制面板(Control Panel)的32位ODBC内,其主要任务是管理安装的ODBC驱动程序和管理数据源。

  驱动程序管理器(Driver Manager)。驱动程序管理器包含在ODBC32.DLL中,对用户是透明的。其任务是管理ODBC驱动程序,是ODBC中最重要的部件。

  ODBC API。

  ODBC 驱动程序。是一些DLL,提供了ODBC和数据库之间的接口。

  数据源。数据源包含了数据库位置和数据库类型等信息,实际上是一种数据连接的抽象。

  各部件之间的关系如图下图所示:

  应用程序要访问一个数据库,首先必须用ODBC管理器注册一个数据源,管理器根据数据源提供的数据库位置、数据库类型及ODBC驱动程序等信息,建立起ODBC与具体数据库的联系。这样,只要应用程序将数据源名提供给ODBC,ODBC就能建立起与相应数据库的连接。

  在ODBC中,ODBC API不能直接访问数据库,必须通过驱动程序管理器与数据库交换信息。驱动程序管理器负责将应用程序对ODBC API的调用传递给正确的驱动程序,而驱动程序在执行完相应的操作后,将结果通过驱动程序管理器返回给应用程序。

  在访问ODBC数据源时需要ODBC驱动程序的支持。用Visual C++ 5.0安装程序可以安装SQL Server、 Access、 Paradox、 dBase、 FoxPro、 Excel、 Oracle 和Microsoft Text等驱动程序.在缺省情况下,VC5.0只会安装SQL Server、 Access、 FoxPro和dBase的驱动程序.如果用户需要安装别的驱动程序,则需要重新运行VC 5.0的安装程序并选择所需的驱动程序。


Visual C++ 中的ODBC编程


篛DBC(Open Database Connectivity,开放式数据库连接),是一种用来在相关或不相关的数据库管理系统(DBMS)中存取数据的标准应用程序接口(API)。本文给出Windows 95 环境下用Visual C++ 进行ODBC 编程的具体方法及技巧。

---- 关键字:ODBC,Visual C++,Windows 编程。

---- 一.概述

---- ODBC 是一种使用SQL 的程序设计接口。使用ODBC 让应用程序的编写者避免了与数据源相联的复杂性。这项技术目前已经得到了大多数DBMS 厂商们的广泛支持。

---- Microsoft Developer Studio 为大多数标准的数据库格式提供了32 位ODBC 驱动器。这些标准数据格式包括有:SQL Server、Access、Paradox、dBase、FoxPro、Excel、Oracle 以及Microsoft Text。如果用户希望使用其他数据格式,用户需要相应的ODBC 驱动器及DBMS。

---- 用户使用自己的DBMS 数据库管理功能生成新的数据库模式后,就可以使用ODBC 来登录数据源。对用户的应用程序来说,只要安装有驱动程序,就能注册很多不同的数据库。登录数据库的具体操作参见有关ODBC 的联机帮助。

---- 二.MFC 提供的ODBC 数据库类

---- Visual C++ 的MFC 基类库定义了几个数据库类。在利用ODBC 编程时,经常要使用到CDatabase( 数据库类),CRecordSet( 记录集类) 和CRecordView( 可视记录集类)。其中:

---- CDatabase 类对象提供了对数据源的连接,通过它你可以对数据源进行操作。

---- CRecordSet 类对象提供了从数据源中提取出的记录集。CRecordSet 对象通常用于两种形式:动态行集(dynasets)和快照集(snapshots)。动态行集能保持与其他用户所做的更改保持同步。快照集则是数据的一个静态视图。每一种形式在记录集被打开时都提供一组记录,所不同的是,当你在一个动态行集里滚动到一条记录时,由其他用户或是你应用程序中的其他记录集对该记录所做的更改会相应地显示出来。

---- CRecordView 类对象能以控制的形式显示数据库记录。这个视图是直接连到一个CRecordSet 对象的表视图。

---- 三.应用ODBC 编程

---- 应用Visual C++ 的AppWizard 可以自动生成一个ODBC 应用程序框架。方法是:打开File 菜单的New 选项,选取Projects,填入工程名,选择MFC AppWizard (exe),然后按AppWizard 的提示进行操作。当AppWizard 询问是否包含数据库支持时,如果你想读写数据库,那么选定Database view with file support;而 阆敕梦适菘獾男畔⒍幌牖匦此龅母谋洌敲囱《―atabase view without file support 选项就比较合适了。选择了数据库支持之后Database Source 按钮会激活,选中它去调用Data Options 对话框。在Database Options 对话框中会显示已向ODBC 注册的数据库资源,选定你所要操作的数据库,如:Super_ES,单击OK 后会出现Select Database Tables 对话框,其中列举了你所选中的数据库中包含的全部表,选择你希望操作的表后,单击OK。在选定了数据库和数据表之后,你可以按照惯例继续进行AppWizard 操作。

---- 特别需要指出的是:在生成的应用程序框架View 类(如:CSuper_ESView)中包含一个指向CSuper_ESSet 对象的指针m_pSet,该指针由AppWizard 建立,目的是在视表单和记录集之间建立联系,使得记录集中的查询结果能够很容易地在视表单上显示出来。有关m_pSet 的详细用法可以参见Visual C++ Online Book。

---- 程序与数据语言建立联系,使用CDatebase::OpenEx() 或CDatabase::Open() 函数来进行初始化。数据库对象必须在你使用它构造一个记录集对象之前被初始化。

---- 下面举例说明在Visual C++ 环境中ODBC 的编程技巧:

---- 1 .查询记录

---- 查询记录使用CRecordSet::Open() 和CRecordSet::Requery() 成员函数。在使用CRecordSet 类对象之前,必须使用CRecordSet::Open() 函数来获得有效的记录集。一旦已经使用过CRecordSet::Open() 函数,再次查询时就可以应用CRecordSet::Requery() 函数。在调用CRecordSet::Open() 函数时,如果已经将一个已经打开的CDatabase 对象指针传给CRecordSet 类对象的m_pDatabase 成员变量,则使用该数据库对象建立ODBC 连接;否则如果m_pDatabase 为空指针,就新建一个CDatabase 类对象并使其与缺省的数据源相连,然后进行CRecordSet 类对象的初始化。缺省数据源由GetDefaultConnect() 函数获得。你也可以提供你所需要的SQL 语句,并以它来调用CRecordSet::Open() 函数,例如:

Super_ESSet.Open(AFX_DATABASE_USE_DEFAULT,strSQL);
---- 如果没有指定参数,程序则使用缺省的SQL 语句,即对在GetDefaultSQL() 函数中指定的SQL 语句进行操作:

CString CSuper_ESSet::GetDefaultSQL()
{return _T("[BasicData],[MainSize]");}
---- 对于GetDefaultSQL() 函数返回的表名,对应的缺省操作是SELECT 语句,即:

SELECT * FROM BasicData,MainSize
---- 查询过程中也可以利用CRecordSet 的成员变量m_strFilter 和m_strSort 来执行条件查询和结果排序。m_strFilter 为过滤字符串,存放着SQL 语句中WHERE 后的条件串;m_strSort 为排序字符串,存放着SQL 语句中ORDER BY 后的字符串。如:

Super_ESSet.m_strFilter="TYPE=电动机";
Super_ESSet.m_strSort="VOLTAGE";
Super_ESSet.Requery();
对应的SQL语句为:
SELECT * FROM BasicData,MainSize 
WHERE TYPE=电动机
ORDER BY VOLTAGE
---- 除了直接赋值给m_strFilter 以外,还可以使用参数化。利用参数化可以更直观,更方便地完成条件查询任务。使用参数化的步骤如下:

---- (1) .声明参变量:

CString p1;
float p2;
---- (2) .在构造函数中初始化参变量

p1=_T("");
p2=0.0f;
m_nParams=2;
---- (3) .将参变量与对应列绑定

pFX- >SetFieldType(CFieldExchange::param)
RFX_Text(pFX,_T("P1"),p1);
RFX_Single(pFX,_T("P2"),p2);
---- 完成以上步骤之后就可以利用参变量进行条件查询了:

m_pSet- >m_strFilter="TYPE=? AND VOLTAGE=?";
m_pSet- >p1=" 电动机";
m_pSet- >p2=60.0;
m_pSet- >Requery();
---- 参变量的值按绑定的顺序替换查询字串中的"?" 适配符。

---- 如果查询的结果是多条记录的话,可以用CRecordSet 类的函数Move(),MoveNext(),MovePrev(),MoveFirst() 和MoveLast() 来移动光标。

---- 2 .增加记录

---- 增加记录使用AddNew() 函数,要求数据库必须是以允许增加的方式打开:

m_pSet- >AddNew(); //在表的末尾增加新记录
m_pSet- >SetFieldNull(&(m_pSet- >m_type), FALSE);
m_pSet- >m_type=" 电动机";
... //输入新的字段值
m_pSet- > Update(); //将新记录存入数据库
m_pSet- >Requery(); //重建记录集
---- 3 .删除记录

---- 直接使用Delete() 函数,并且在调用Delete() 函数之后不需调用Update() 函数:

m_pSet- >Delete();
if (!m_pSet- >IsEOF())
m_pSet- >MoveNext();
else
m_pSet- >MoveLast();
---- 4 .修改记录

---- 修改记录使用Edit() 函数:

m_pSet- >Edit(); //修改当前记录
m_pSet- >m_type="发电机";
//修改当前记录字段值
...
m_pSet- >Update(); //将修改结果存入数据库
m_pSet- >Requery();
---- 5 .撤消操作

---- 如果用户选择了增加或者修改记录后希望放弃当前操作,可以在调用Update() 函数之前调用:

CRecordSet::Move(AFX_MOVE_REFRESH);
---- 来撤消增加或修改模式,并恢复在增加或修改模式之前的当前记录。其中的参数AFX_MOVE_REFRESH 的值为零。

---- 6 .数据库连接的复用

---- 在CRecordSet 类中定义了一个成员变量m_pDatabase:

CDatabase* m_pDatabase;
---- 它是指向对象数据库类的指针。如果在CRecordSet 类对象调用Open() 函数之前,将一个已经打开的CDatabase 类对象指针传给m_pDatabase,就能共享相同的CDatabase 类对象。如:

CDatabase m_db;
CRecordSet m_set1,m_set2;
m_db.Open(_T("Super_ES"));//建立ODBC连接
m_set1.m_pDatabase=&m_db;
//m_set1复用m_db对象
m_set2.m_pDatabse=&m_db; 
// m_set2复用m_db对象
---- 7 .SQL 语句的直接执行

---- 虽然通过CRecordSet 类,我们可以完成大多数的查询操作,而且在CRecordSet::Open() 函数中也可以提供SQL 语句,但是有的时候我们还想进行一些其他操作,例如建立新表,删除表,建立新的字段等等,这时就需要使用到CDatabase 类的直接执行SQL 语句的机制。通过调用CDatabase::ExecuteSQL() 函数来完成SQL 语句的直接执行:

BOOL CDB::ExecuteSQLAndReportFailure(const CString& strSQL)
{
TRY
{
m_pdb- >ExecuteSQL(strSQL);//直接执行SQL语句
}
CATCH (CDBException,e)
{
CString strMsg;
strMsg.LoadString(IDS_EXECUTE_SQL_FAILED);
strMsg+=strSQL;
return FALSE;
}
END_CATCH 
return TRUE;
}
---- 应当指出的是,由于不同DBMS 提供的数据操作语句不尽相同,直接执行SQL 语句可能会破坏软件的DBMS 无关性,因此在应用中应当慎用此类操作。

---- 8 .动态连接表

---- 表的动态连接可以利用在调用CRecordSet::Open() 函数时指定SQL 语句来实现。同一个记录集对象只能访问具有相同结构的表,否则查询结果将无法与变量相对应。

void CDB::ChangeTable()
{
if (m_pSet- >IsOpen()) m_pSet- >Close();
switch (m_id)
{
case 0:
m_pSet- >Open(AFX_DB_USE_DEFAULT_TYPE, 
"SELECT * FROM SLOT0"); //连接表SLOT0
m_id=1;
break;
case 1:
m_pSet- >Open(AFX_DB_USE_DEFAULT_TYPE, 
"SELECT * FROM SLOT1"); //连接表SLOT1
m_id=0;
break;
}
}
---- 9 .动态连接数据库

---- 由于与数据库的连接是通过CDatabase 类对象来实现的,所以我们可以通过赋与CRecordSet 类对象参数m_pDatabase 以连接不同数据库的CDatabase 对象指针,就可以动态连接数据库。

void CDB::ChangeConnect()
{
CDatabase* pdb=m_pSet- >m_pDatabase;
pdb- >Close();

switch (m_id)
{
case 0:
if (!pdb- >Open(_T("Super_ES"))) 
//连接数据源Super_ES
{
AfxMessageBox("数据源Super_ES打开失败,"
"请检查相应的ODBC连接", MB_OK|MB_ICONWARNING);
exit(0);
}
m_id=1;
break;
case 1:
if (!pdb- >Open(_T("Motor")))
//连接数据源Motor
{
AfxMessageBox("数据源Motor打开失败,"
"请检查相应的ODBC连接", MB_OK|MB_ICONWARNING);
exit(0);
}
m_id=0;
break;
}
}
---- 四.总结

---- Visual C++ 中的ODBC 类库可以帮助程序员完成绝大多数的数据库操作。利用ODBC 技术使得程序员从具体的DBMS 中解脱出来,从而极大的减少了软件开发的工作量,缩短开发周期,提高了效率和软件的可靠性。本文总结的笔者从事软件开发的一些经验心得希望对从事ODBC 开发的工作者有所帮助。


用Visual C++开发数据库应用程序
 

1、 概述

1、1 Visual C++开发数据库技术的特点

Visual C++提供了多种多样的数据库访问技术——ODBC API、MFC ODBC、DAO、OLE DB、ADO等。这些技术各有自己的特点,它们提供了简单、灵活、访问速度快、可扩展性好的开发技术。


简单性

Visual C++中提供了MFC类库、ATL模板类以及AppWizard、ClassWizard等一系列的Wizard工具用于帮助用户快速的建立自己的应用程序,大大简化了应用程序的设计。使用这些技术,可以使开发者编写很少的代码或不需编写代码就可以开发一个数据库应用程序。


灵活性

Visual C++提供的开发环境可以使开发者根据自己的需要设计应用程序的界面和功能,而且,Visual C++提供了丰富的类库和方法,可以使开发者根据自己的应用特点进行选择。


访问速度快

为了解决ODBC开发的数据库应用程序访问数据库的速度慢的问题,Visual C++提供了新的访问技术——OLE DB和ADO,OLE DB和ADO都是基于COM接口的技术,使用这种技术可以直接对数据库的驱动程序进行访问,这大大提供了访问速度。


可扩展性

Visual C++提供了OLE技术和ActiveX技术,这种技术可以增强应用程序的能力。使用OLE技术和ActiveX技术可以使开发者利用Visual C++中提供的各种组件、控件以及第三方开发者提供的组件来创建自己的程序,从而实现应用程序的组件化。使用这种技术可以使应用程序具有良好的可扩展性。


访问不同种类数据源

传统的ODBC技术只能访问关系型数据库,在Visual C++中,提供了OLE DB访问技术,不仅可以访问关系型数据库,还可以访问非关系型数据库。

1、2 Visual C++开发数据库技术

Visual C++提供了多种访问数据库的技术,如下所示:


ODBC(Open DataBase Connectivity)


MFC ODBC(Microsoft Foundation Classes ODBC)


DAO (Data Access Object)


OLE DB(Object Link and Embedding DataBase)


ADO(ActiveX Data Object)

这些技术各有自己的特点,总结如下:


ODBC

ODBC是客户应用程序访问关系数据库时提供的一个统一的接口,对于不同的数据库,ODBC提供了一套统一的API,使应用程序可以应用所提供的API来访问任何提供了ODBC驱动程序的数据库。而且,ODBC已经成为一种标准,所以,目前所有的关系数据库都提供了ODBC驱动程序,这使ODBC的应用非常广泛,基本上可用于所有的关系数据库。

但由于ODBC只能用于关系数据库,使得利用ODBC很难访问对象数据库及其它非关系数据库。

由于ODBC是一种底层的访问技术,因些,ODBC API可以使客户应用程序能够从底层设置和控制数据库,完成一些高层数据库技术无法完成的功能。


MFC ODBC

由于直接使用ODBC API编写应用程序要编制大量代码,在Visual C++中提供了MFC ODBC类,封装了ODBC API,这使得利用MFC来创建ODBC的应用程序非常简便。


DAO

DAO提供了一种通过程序代码创建和操纵数据库的机制。多个DAO构成一个体系结构,在这个结构中,各个DAO对象协同工作。MFC DAO是微软提供的用于访问Microsoft Jet数据库文件(*.mdb)的强有力的数据库开发工具,它通过DAO的封装,向程序员提供了DAO丰富的操作数据库手段。


OLE DB

OLE DB是Visual C++开发数据库应用中提供的新技术,它基于COM接口。因此,OLE DB对所有的文件系统包括关系数据库和非关系数据库都提供了统一的接口。这些特性使得OLE DB技术比传统的数据库访问技术更加优越。

与ODBC技术相似,OLE DB属于数据库访问技术中的底层接口。

直接使用OLE DB来设计数据库应用程序需要大量的代码。在VC中提供了ATL模板,用于设计OLE DB数据应用程序和数据提供程序。


ADO

ADO技术是基于OLE DB的访问接口,它继承了OLE DB技术的优点,并且,ADO对OLE DB的接口作了封装,定义了ADO对象,使程序开发得到简化,ADO技术属于数据库访问的高层接口。

 

2、 使用ODBC API

Microsoft 开放数据库互连(ODBC,Open DataBase Connectivity)是Microsoft Windows 开放服务体系(WOSA)的一部分,是一个数据库访问的标准接口。使用这一标准接口,我们可以不关心具体的数据库管理系统(DBMS)的细节,而只要有相应类型数据库的ODBC驱动程序,就可以实现对数据库的访问。

ODBC编程接口为我们提供了极大的灵活性,我们可以通过这一个接口访问不同种类的数据库。而且,通过相应的ODBC驱动程序,我们可以方便地实现不同数据类型之间的转换。

2.1 ODBC API 概述

ODBC是一个应用广泛的数据库访问应用编程接口(API),使用标准的SQL(结构化查询语言)作为其数据库访问语言。

2.11体系结构

ODBC的结构是建立在客户机/服务器体系结构之上,它包含如下四个部分:

应用程序(Application ):

应用程序即用户的应用,它负责用户与用户接口之间的交互操作,以及调用ODBC函数以给出SQL请求并提取结果以及进行错误处理。

ODBC驱动程序管理器(Driver Manager):

ODBC驱动程序管理器为应用程序加载和调用驱动程序,它可以同时管理多个应用程序和多个驱动程序。它的功能是通过间接调用函数和使用动态链接库(DLL)来实现的,因此它一般包含在扩展名为”DLL”的文件中。

ODBC驱动程序(Driver)

ODBC 驱动程序执行ODBC函数调用,呈送 SQL 请求给指定的数据源,并将结果返回给应用程序。驱动程序也负责与任何访问数据源的必要软件层进行交互作用,这种层包括与底层网络或文件系统接口的软件。

数据源

数据源由数据集和与其相关联的环境组成,包括操作系统、DBMS 和网络(如果存在的话)。ODBC 通过引入“数据源”的概念解决了网络拓扑结构和主机的大范围差异问题,这样,用户看到的是数据源的名称而不必关心其它东西。

 

2.12数据类型

ODBC使用两类数据类型:SQL数据类型和C数据类型。SQL数据类型用于数据源,C数据类型用于应用程序代码中。

2.13句柄

ODBC API 实现数据库操作的手段是语句,这是一个强有力的手段。ODBC语句除了能执行SQL语句和完成查询操作之外,还能实现大多数数据库操作。

在ODBC中,使用不同的句柄(HANDLE)来标志环境(ENVIRONMENT)、连接(CONNECTION)、语句(STATEMENT)、描述器(DESCRIPTOR)等。

句柄就是一个应用程序变量,系统用它来存储关于应用程序的上下文信息和应用程序所用到的一些对象。它和 Windows 编程中的概念类似,不过ODBC 更加完善了句柄的作用。

1、 环境句柄是 ODBC 中整个上下文的句柄,使用 ODBC 的每个程序从创建环境句柄开始,以释放环境句柄结束。所有其它的句柄(这一应用程序所有的联接句柄和语句句柄)都由环境句柄中的上下文来管理。环境句柄在每个应用程序中只能创建一个。

2、联接句柄管理有关联接的所有信息。联接句柄可以分配多个,这不仅合法而且很有用;但不要生成不必要的句柄以免资源的浪费。但是,不同的驱动程序支持的联接情况有所不同,有的驱动程序在一个应用程序中仅支持一个联接句柄,有的驱动程序仅支持一个语句句柄。在应用程序中,可以在任何适当的时候联接或脱离数据源,但不要轻易地建立或脱离联接。

3、语句句柄是 ODBC API 真正发挥重要作用的,它被用来处理 SQL 语句及目录函数,每个语句句柄只与一个联接有关。当驱动程序接收一个来自应用程序的函数调用指令而该指令包含一个语句句柄时,驱动程序管理器将使用存储在语句句柄中的联接句柄来将这一函数调用发送给合适的驱动程序。

4、描述器句柄是元数据的集合,这些元数据描述了SQL语句的参数、记录集的列等信息。当有语句被分配内存之后,描述器自动生成,称为自动分配描述器。在程序中,应用程序也可调用SQLAllocHandle分配描述器。

当应用程序调用API函数SQLAllocHandle时,驱动管理器或者ODBC驱动程序将为所声明的句柄类型分配内部结构,返回句柄值。

2.14异常处理

为了在程序开发过程中调试程序,发现程序错误,ODBC API通过两种方式返回有关ODBC API函数执行的的信息:返回码和诊断记录。返回码返回函数执行的返回值,说明函数执行成功与否。诊断记录说明函数执行的详细信息。


返回码(Return Code)

每一个ODBC API函数都返回一个代码——返回码,指示函数执行的成功与否。如果函数调用成功,返回码为SQL_SUCCESS或SQL_SUCCESS_WITH_INFO。SQL_SUCCESS指示可通过诊断记录获取有关操作的详细信息,SQL_SUCCESS_WITH_INFO指示应用程序执行结果带有警告信息,可通过诊断记录获取详细的信息。如果函数调用失败,返回码为SQL_ERROR。

下面的一段代码根据函数SQLFetch()执行的返回码,判断函数执行的成功与否,从而据此进行相应的处理。

 

SQLRETURN rtcode;

SQLHSTMT hstmt;

While(rtcode=SQLFetch(hstmt)!=SQL_NO_DATA)

{

if(rtcode==SQL_SUCCESS_WITH_INFO)

{

//显示警告信息

}

else

{

//显示出错信息

break;

}

//函数调用成功,进行处理

}

如果程序执行错误,返回码为SQL_INVALID_HANDLE,程序无法执行,而其它的返回码都带有程序执行的信息。


诊断记录(Diagnostic Records)

每个ODBC API函数都能够产生一系列的反映操作信息的诊断记录。这些诊断记录放在相关连的ODBC句柄中,直到下一个使用同一个句柄的函数调用,该诊断记录一直存在。诊断记录的大小没有限制。

诊断记录有两类:头记录(Head Record)和状态记录(Status Record)。头记录是第一版权法记录(Record 0),后面的记录为状态记录。诊断记录有许多的域组成,这些域在头记录和状态记录中是不同的。

可以用SQLGetDiagField函数获取诊断记录中的特定的域,另外,可以使用SQLGetDiagRec()获取诊断记录中一些常用的域,如SQLSTATE、原始错误号等。


头记录

头记录的各个域中包含了一个函数执行的通用信息,无论函数执行成功与否,只要不返回SQL_INVALID_HANDLE,都会生成头记录。


状态记录

状态记录中的每个域包含了驱动管理器、ODBC驱动程序或数据源返回的特定的错误或警告信息,包括SQLSTATE、原始错误码、诊断信息、列号和行号等。只有函数执行返回SQL_ERROR,SQL_STILL_EXEUTING、SQL_SUCCESS_WITH_INFO、SQL_NEED_DATA或SQL_NO_DATA时,才会生成诊断记录。


使用SQLGetDiagRec和SQLGetDiagField

应用程序可以调用函数SQLGetDiagRec或SQLGetDiagField获取诊断信息。对于给定的句柄,这两个函数返回最近使用该句柄的函数的诊断信息。当有使用该句柄的函数执行时,句柄记录所记录的原有的诊断信息被覆盖。如果函数执行后产生多个状态记录,程序必须多次调用这两个函数以获取信息。
 

2.2 应用ODBC API建立应用程序

虽然直接应用ODBC API编制应用程序相对来说较为繁琐,但是,由于直接使用ODBC API编写的程序相对要简洁、高效。所以,我们有必要学习直接使用ODBC API编程。

一般地,编写ODBC程序主要有以下几个步骤:


分配ODBC环境


分配连接句柄


连接数据源


构造和执行SQL语句


取得执行结果


断开同数据源的连接


释放ODBC环境

2.21 分配ODBC环境

对于任何ODBC应用程序来说,第一步的工作是装载驱动程序管理器,然后初始化ODBC环境,分配环境句柄。

首先,程序中声明一个SQLHENV类型的变量,然后调用函数SQLAllocHandle,向其中传递分配的上述SQLHENV类型的变量地址和SQL_HANDLE_ENV选项。如下代码所示:

SQLHENV henv;

SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv);

执行该调用语句后,驱动程序分配一个结构,该结构中存放环境信息,然后返回对应于该环境的环境句柄。

2.22分配连接句柄

分配环境句柄后,在建立至数据源的连接之前,我们必须分配一个连接句柄,每一个到数据源的连接对应于一个连接句柄。

首先,程序定义了一个SQLHDBC类型的变量,用于存放连接句柄,然后调用SQLAllocHandle函数分配句柄。如下代码所示:

SQLHDBC hdbc;

SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc);

henv为环境句柄。
 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.2 应用ODBC API建立应用程序

虽然直接应用ODBC API编制应用程序相对来说较为繁琐,但是,由于直接使用ODBC API编写的程序相对要简洁、高效。所以,我们有必要学习直接使用ODBC API编程。

一般地,编写ODBC程序主要有以下几个步骤:


分配ODBC环境


分配连接句柄


连接数据源


构造和执行SQL语句


取得执行结果


断开同数据源的连接


释放ODBC环境

2.21 分配ODBC环境

对于任何ODBC应用程序来说,第一步的工作是装载驱动程序管理器,然后初始化ODBC环境,分配环境句柄。

首先,程序中声明一个SQLHENV类型的变量,然后调用函数SQLAllocHandle,向其中传递分配的上述SQLHENV类型的变量地址和SQL_HANDLE_ENV选项。如下代码所示:

SQLHENV henv;

SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv);

执行该调用语句后,驱动程序分配一个结构,该结构中存放环境信息,然后返回对应于该环境的环境句柄。

2.22分配连接句柄

分配环境句柄后,在建立至数据源的连接之前,我们必须分配一个连接句柄,每一个到数据源的连接对应于一个连接句柄。

首先,程序定义了一个SQLHDBC类型的变量,用于存放连接句柄,然后调用SQLAllocHandle函数分配句柄。如下代码所示:

SQLHDBC hdbc;

SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc);

henv为环境句柄。
 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.12数据类型

ODBC使用两类数据类型:SQL数据类型和C数据类型。SQL数据类型用于数据源,C数据类型用于应用程序代码中。

2.13句柄

ODBC API 实现数据库操作的手段是语句,这是一个强有力的手段。ODBC语句除了能执行SQL语句和完成查询操作之外,还能实现大多数数据库操作。

在ODBC中,使用不同的句柄(HANDLE)来标志环境(ENVIRONMENT)、连接(CONNECTION)、语句(STATEMENT)、描述器(DESCRIPTOR)等。

句柄就是一个应用程序变量,系统用它来存储关于应用程序的上下文信息和应用程序所用到的一些对象。它和 Windows 编程中的概念类似,不过ODBC 更加完善了句柄的作用。

1、 环境句柄是 ODBC 中整个上下文的句柄,使用 ODBC 的每个程序从创建环境句柄开始,以释放环境句柄结束。所有其它的句柄(这一应用程序所有的联接句柄和语句句柄)都由环境句柄中的上下文来管理。环境句柄在每个应用程序中只能创建一个。

2、联接句柄管理有关联接的所有信息。联接句柄可以分配多个,这不仅合法而且很有用;但不要生成不必要的句柄以免资源的浪费。但是,不同的驱动程序支持的联接情况有所不同,有的驱动程序在一个应用程序中仅支持一个联接句柄,有的驱动程序仅支持一个语句句柄。在应用程序中,可以在任何适当的时候联接或脱离数据源,但不要轻易地建立或脱离联接。

3、语句句柄是 ODBC API 真正发挥重要作用的,它被用来处理 SQL 语句及目录函数,每个语句句柄只与一个联接有关。当驱动程序接收一个来自应用程序的函数调用指令而该指令包含一个语句句柄时,驱动程序管理器将使用存储在语句句柄中的联接句柄来将这一函数调用发送给合适的驱动程序。

4、描述器句柄是元数据的集合,这些元数据描述了SQL语句的参数、记录集的列等信息。当有语句被分配内存之后,描述器自动生成,称为自动分配描述器。在程序中,应用程序也可调用SQLAllocHandle分配描述器。

当应用程序调用API函数SQLAllocHandle时,驱动管理器或者ODBC驱动程序将为所声明的句柄类型分配内部结构,返回句柄值。

2.14异常处理

为了在程序开发过程中调试程序,发现程序错误,ODBC API通过两种方式返回有关ODBC API函数执行的的信息:返回码和诊断记录。返回码返回函数执行的返回值,说明函数执行成功与否。诊断记录说明函数执行的详细信息。


返回码(Return Code)

每一个ODBC API函数都返回一个代码——返回码,指示函数执行的成功与否。如果函数调用成功,返回码为SQL_SUCCESS或SQL_SUCCESS_WITH_INFO。SQL_SUCCESS指示可通过诊断记录获取有关操作的详细信息,SQL_SUCCESS_WITH_INFO指示应用程序执行结果带有警告信息,可通过诊断记录获取详细的信息。如果函数调用失败,返回码为SQL_ERROR。

下面的一段代码根据函数SQLFetch()执行的返回码,判断函数执行的成功与否,从而据此进行相应的处理。

 

SQLRETURN rtcode;

SQLHSTMT hstmt;

While(rtcode=SQLFetch(hstmt)!=SQL_NO_DATA)

{

if(rtcode==SQL_SUCCESS_WITH_INFO)

{

//显示警告信息

}

else

{

//显示出错信息

break;

}

//函数调用成功,进行处理

}

如果程序执行错误,返回码为SQL_INVALID_HANDLE,程序无法执行,而其它的返回码都带有程序执行的信息。


诊断记录(Diagnostic Records)

每个ODBC API函数都能够产生一系列的反映操作信息的诊断记录。这些诊断记录放在相关连的ODBC句柄中,直到下一个使用同一个句柄的函数调用,该诊断记录一直存在。诊断记录的大小没有限制。

诊断记录有两类:头记录(Head Record)和状态记录(Status Record)。头记录是第一版权法记录(Record 0),后面的记录为状态记录。诊断记录有许多的域组成,这些域在头记录和状态记录中是不同的。

可以用SQLGetDiagField函数获取诊断记录中的特定的域,另外,可以使用SQLGetDiagRec()获取诊断记录中一些常用的域,如SQLSTATE、原始错误号等。


头记录

头记录的各个域中包含了一个函数执行的通用信息,无论函数执行成功与否,只要不返回SQL_INVALID_HANDLE,都会生成头记录。


状态记录

状态记录中的每个域包含了驱动管理器、ODBC驱动程序或数据源返回的特定的错误或警告信息,包括SQLSTATE、原始错误码、诊断信息、列号和行号等。只有函数执行返回SQL_ERROR,SQL_STILL_EXEUTING、SQL_SUCCESS_WITH_INFO、SQL_NEED_DATA或SQL_NO_DATA时,才会生成诊断记录。


使用SQLGetDiagRec和SQLGetDiagField

应用程序可以调用函数SQLGetDiagRec或SQLGetDiagField获取诊断信息。对于给定的句柄,这两个函数返回最近使用该句柄的函数的诊断信息。当有使用该句柄的函数执行时,句柄记录所记录的原有的诊断信息被覆盖。如果函数执行后产生多个状态记录,程序必须多次调用这两个函数以获取信息。
 

2.2 应用ODBC API建立应用程序

虽然直接应用ODBC API编制应用程序相对来说较为繁琐,但是,由于直接使用ODBC API编写的程序相对要简洁、高效。所以,我们有必要学习直接使用ODBC API编程。

一般地,编写ODBC程序主要有以下几个步骤:


分配ODBC环境


分配连接句柄


连接数据源


构造和执行SQL语句


取得执行结果


断开同数据源的连接


释放ODBC环境

2.21 分配ODBC环境

对于任何ODBC应用程序来说,第一步的工作是装载驱动程序管理器,然后初始化ODBC环境,分配环境句柄。

首先,程序中声明一个SQLHENV类型的变量,然后调用函数SQLAllocHandle,向其中传递分配的上述SQLHENV类型的变量地址和SQL_HANDLE_ENV选项。如下代码所示:

SQLHENV henv;

SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv);

执行该调用语句后,驱动程序分配一个结构,该结构中存放环境信息,然后返回对应于该环境的环境句柄。

2.22分配连接句柄

分配环境句柄后,在建立至数据源的连接之前,我们必须分配一个连接句柄,每一个到数据源的连接对应于一个连接句柄。

首先,程序定义了一个SQLHDBC类型的变量,用于存放连接句柄,然后调用SQLAllocHandle函数分配句柄。如下代码所示:

SQLHDBC hdbc;

SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc);

henv为环境句柄。
 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.2 应用ODBC API建立应用程序

虽然直接应用ODBC API编制应用程序相对来说较为繁琐,但是,由于直接使用ODBC API编写的程序相对要简洁、高效。所以,我们有必要学习直接使用ODBC API编程。

一般地,编写ODBC程序主要有以下几个步骤:


分配ODBC环境


分配连接句柄


连接数据源


构造和执行SQL语句


取得执行结果


断开同数据源的连接


释放ODBC环境

2.21 分配ODBC环境

对于任何ODBC应用程序来说,第一步的工作是装载驱动程序管理器,然后初始化ODBC环境,分配环境句柄。

首先,程序中声明一个SQLHENV类型的变量,然后调用函数SQLAllocHandle,向其中传递分配的上述SQLHENV类型的变量地址和SQL_HANDLE_ENV选项。如下代码所示:

SQLHENV henv;

SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv);

执行该调用语句后,驱动程序分配一个结构,该结构中存放环境信息,然后返回对应于该环境的环境句柄。

2.22分配连接句柄

分配环境句柄后,在建立至数据源的连接之前,我们必须分配一个连接句柄,每一个到数据源的连接对应于一个连接句柄。

首先,程序定义了一个SQLHDBC类型的变量,用于存放连接句柄,然后调用SQLAllocHandle函数分配句柄。如下代码所示:

SQLHDBC hdbc;

SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc);

henv为环境句柄。
 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2、 使用ODBC API

Microsoft 开放数据库互连(ODBC,Open DataBase Connectivity)是Microsoft Windows 开放服务体系(WOSA)的一部分,是一个数据库访问的标准接口。使用这一标准接口,我们可以不关心具体的数据库管理系统(DBMS)的细节,而只要有相应类型数据库的ODBC驱动程序,就可以实现对数据库的访问。

ODBC编程接口为我们提供了极大的灵活性,我们可以通过这一个接口访问不同种类的数据库。而且,通过相应的ODBC驱动程序,我们可以方便地实现不同数据类型之间的转换。

2.1 ODBC API 概述

ODBC是一个应用广泛的数据库访问应用编程接口(API),使用标准的SQL(结构化查询语言)作为其数据库访问语言。

2.11体系结构

ODBC的结构是建立在客户机/服务器体系结构之上,它包含如下四个部分:

应用程序(Application ):

应用程序即用户的应用,它负责用户与用户接口之间的交互操作,以及调用ODBC函数以给出SQL请求并提取结果以及进行错误处理。

ODBC驱动程序管理器(Driver Manager):

ODBC驱动程序管理器为应用程序加载和调用驱动程序,它可以同时管理多个应用程序和多个驱动程序。它的功能是通过间接调用函数和使用动态链接库(DLL)来实现的,因此它一般包含在扩展名为”DLL”的文件中。

ODBC驱动程序(Driver)

ODBC 驱动程序执行ODBC函数调用,呈送 SQL 请求给指定的数据源,并将结果返回给应用程序。驱动程序也负责与任何访问数据源的必要软件层进行交互作用,这种层包括与底层网络或文件系统接口的软件。

数据源

数据源由数据集和与其相关联的环境组成,包括操作系统、DBMS 和网络(如果存在的话)。ODBC 通过引入“数据源”的概念解决了网络拓扑结构和主机的大范围差异问题,这样,用户看到的是数据源的名称而不必关心其它东西。

 

2.12数据类型

ODBC使用两类数据类型:SQL数据类型和C数据类型。SQL数据类型用于数据源,C数据类型用于应用程序代码中。

2.13句柄

ODBC API 实现数据库操作的手段是语句,这是一个强有力的手段。ODBC语句除了能执行SQL语句和完成查询操作之外,还能实现大多数数据库操作。

在ODBC中,使用不同的句柄(HANDLE)来标志环境(ENVIRONMENT)、连接(CONNECTION)、语句(STATEMENT)、描述器(DESCRIPTOR)等。

句柄就是一个应用程序变量,系统用它来存储关于应用程序的上下文信息和应用程序所用到的一些对象。它和 Windows 编程中的概念类似,不过ODBC 更加完善了句柄的作用。

1、 环境句柄是 ODBC 中整个上下文的句柄,使用 ODBC 的每个程序从创建环境句柄开始,以释放环境句柄结束。所有其它的句柄(这一应用程序所有的联接句柄和语句句柄)都由环境句柄中的上下文来管理。环境句柄在每个应用程序中只能创建一个。

2、联接句柄管理有关联接的所有信息。联接句柄可以分配多个,这不仅合法而且很有用;但不要生成不必要的句柄以免资源的浪费。但是,不同的驱动程序支持的联接情况有所不同,有的驱动程序在一个应用程序中仅支持一个联接句柄,有的驱动程序仅支持一个语句句柄。在应用程序中,可以在任何适当的时候联接或脱离数据源,但不要轻易地建立或脱离联接。

3、语句句柄是 ODBC API 真正发挥重要作用的,它被用来处理 SQL 语句及目录函数,每个语句句柄只与一个联接有关。当驱动程序接收一个来自应用程序的函数调用指令而该指令包含一个语句句柄时,驱动程序管理器将使用存储在语句句柄中的联接句柄来将这一函数调用发送给合适的驱动程序。

4、描述器句柄是元数据的集合,这些元数据描述了SQL语句的参数、记录集的列等信息。当有语句被分配内存之后,描述器自动生成,称为自动分配描述器。在程序中,应用程序也可调用SQLAllocHandle分配描述器。

当应用程序调用API函数SQLAllocHandle时,驱动管理器或者ODBC驱动程序将为所声明的句柄类型分配内部结构,返回句柄值。

2.14异常处理

为了在程序开发过程中调试程序,发现程序错误,ODBC API通过两种方式返回有关ODBC API函数执行的的信息:返回码和诊断记录。返回码返回函数执行的返回值,说明函数执行成功与否。诊断记录说明函数执行的详细信息。


返回码(Return Code)

每一个ODBC API函数都返回一个代码——返回码,指示函数执行的成功与否。如果函数调用成功,返回码为SQL_SUCCESS或SQL_SUCCESS_WITH_INFO。SQL_SUCCESS指示可通过诊断记录获取有关操作的详细信息,SQL_SUCCESS_WITH_INFO指示应用程序执行结果带有警告信息,可通过诊断记录获取详细的信息。如果函数调用失败,返回码为SQL_ERROR。

下面的一段代码根据函数SQLFetch()执行的返回码,判断函数执行的成功与否,从而据此进行相应的处理。

 

SQLRETURN rtcode;

SQLHSTMT hstmt;

While(rtcode=SQLFetch(hstmt)!=SQL_NO_DATA)

{

if(rtcode==SQL_SUCCESS_WITH_INFO)

{

//显示警告信息

}

else

{

//显示出错信息

break;

}

//函数调用成功,进行处理

}

如果程序执行错误,返回码为SQL_INVALID_HANDLE,程序无法执行,而其它的返回码都带有程序执行的信息。


诊断记录(Diagnostic Records)

每个ODBC API函数都能够产生一系列的反映操作信息的诊断记录。这些诊断记录放在相关连的ODBC句柄中,直到下一个使用同一个句柄的函数调用,该诊断记录一直存在。诊断记录的大小没有限制。

诊断记录有两类:头记录(Head Record)和状态记录(Status Record)。头记录是第一版权法记录(Record 0),后面的记录为状态记录。诊断记录有许多的域组成,这些域在头记录和状态记录中是不同的。

可以用SQLGetDiagField函数获取诊断记录中的特定的域,另外,可以使用SQLGetDiagRec()获取诊断记录中一些常用的域,如SQLSTATE、原始错误号等。


头记录

头记录的各个域中包含了一个函数执行的通用信息,无论函数执行成功与否,只要不返回SQL_INVALID_HANDLE,都会生成头记录。


状态记录

状态记录中的每个域包含了驱动管理器、ODBC驱动程序或数据源返回的特定的错误或警告信息,包括SQLSTATE、原始错误码、诊断信息、列号和行号等。只有函数执行返回SQL_ERROR,SQL_STILL_EXEUTING、SQL_SUCCESS_WITH_INFO、SQL_NEED_DATA或SQL_NO_DATA时,才会生成诊断记录。


使用SQLGetDiagRec和SQLGetDiagField

应用程序可以调用函数SQLGetDiagRec或SQLGetDiagField获取诊断信息。对于给定的句柄,这两个函数返回最近使用该句柄的函数的诊断信息。当有使用该句柄的函数执行时,句柄记录所记录的原有的诊断信息被覆盖。如果函数执行后产生多个状态记录,程序必须多次调用这两个函数以获取信息。
 

2.2 应用ODBC API建立应用程序

虽然直接应用ODBC API编制应用程序相对来说较为繁琐,但是,由于直接使用ODBC API编写的程序相对要简洁、高效。所以,我们有必要学习直接使用ODBC API编程。

一般地,编写ODBC程序主要有以下几个步骤:


分配ODBC环境


分配连接句柄


连接数据源


构造和执行SQL语句


取得执行结果


断开同数据源的连接


释放ODBC环境

2.21 分配ODBC环境

对于任何ODBC应用程序来说,第一步的工作是装载驱动程序管理器,然后初始化ODBC环境,分配环境句柄。

首先,程序中声明一个SQLHENV类型的变量,然后调用函数SQLAllocHandle,向其中传递分配的上述SQLHENV类型的变量地址和SQL_HANDLE_ENV选项。如下代码所示:

SQLHENV henv;

SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv);

执行该调用语句后,驱动程序分配一个结构,该结构中存放环境信息,然后返回对应于该环境的环境句柄。

2.22分配连接句柄

分配环境句柄后,在建立至数据源的连接之前,我们必须分配一个连接句柄,每一个到数据源的连接对应于一个连接句柄。

首先,程序定义了一个SQLHDBC类型的变量,用于存放连接句柄,然后调用SQLAllocHandle函数分配句柄。如下代码所示:

SQLHDBC hdbc;

SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc);

henv为环境句柄。
 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.2 应用ODBC API建立应用程序

虽然直接应用ODBC API编制应用程序相对来说较为繁琐,但是,由于直接使用ODBC API编写的程序相对要简洁、高效。所以,我们有必要学习直接使用ODBC API编程。

一般地,编写ODBC程序主要有以下几个步骤:


分配ODBC环境


分配连接句柄


连接数据源


构造和执行SQL语句


取得执行结果


断开同数据源的连接


释放ODBC环境

2.21 分配ODBC环境

对于任何ODBC应用程序来说,第一步的工作是装载驱动程序管理器,然后初始化ODBC环境,分配环境句柄。

首先,程序中声明一个SQLHENV类型的变量,然后调用函数SQLAllocHandle,向其中传递分配的上述SQLHENV类型的变量地址和SQL_HANDLE_ENV选项。如下代码所示:

SQLHENV henv;

SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv);

执行该调用语句后,驱动程序分配一个结构,该结构中存放环境信息,然后返回对应于该环境的环境句柄。

2.22分配连接句柄

分配环境句柄后,在建立至数据源的连接之前,我们必须分配一个连接句柄,每一个到数据源的连接对应于一个连接句柄。

首先,程序定义了一个SQLHDBC类型的变量,用于存放连接句柄,然后调用SQLAllocHandle函数分配句柄。如下代码所示:

SQLHDBC hdbc;

SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc);

henv为环境句柄。
 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.12数据类型

ODBC使用两类数据类型:SQL数据类型和C数据类型。SQL数据类型用于数据源,C数据类型用于应用程序代码中。

2.13句柄

ODBC API 实现数据库操作的手段是语句,这是一个强有力的手段。ODBC语句除了能执行SQL语句和完成查询操作之外,还能实现大多数数据库操作。

在ODBC中,使用不同的句柄(HANDLE)来标志环境(ENVIRONMENT)、连接(CONNECTION)、语句(STATEMENT)、描述器(DESCRIPTOR)等。

句柄就是一个应用程序变量,系统用它来存储关于应用程序的上下文信息和应用程序所用到的一些对象。它和 Windows 编程中的概念类似,不过ODBC 更加完善了句柄的作用。

1、 环境句柄是 ODBC 中整个上下文的句柄,使用 ODBC 的每个程序从创建环境句柄开始,以释放环境句柄结束。所有其它的句柄(这一应用程序所有的联接句柄和语句句柄)都由环境句柄中的上下文来管理。环境句柄在每个应用程序中只能创建一个。

2、联接句柄管理有关联接的所有信息。联接句柄可以分配多个,这不仅合法而且很有用;但不要生成不必要的句柄以免资源的浪费。但是,不同的驱动程序支持的联接情况有所不同,有的驱动程序在一个应用程序中仅支持一个联接句柄,有的驱动程序仅支持一个语句句柄。在应用程序中,可以在任何适当的时候联接或脱离数据源,但不要轻易地建立或脱离联接。

3、语句句柄是 ODBC API 真正发挥重要作用的,它被用来处理 SQL 语句及目录函数,每个语句句柄只与一个联接有关。当驱动程序接收一个来自应用程序的函数调用指令而该指令包含一个语句句柄时,驱动程序管理器将使用存储在语句句柄中的联接句柄来将这一函数调用发送给合适的驱动程序。

4、描述器句柄是元数据的集合,这些元数据描述了SQL语句的参数、记录集的列等信息。当有语句被分配内存之后,描述器自动生成,称为自动分配描述器。在程序中,应用程序也可调用SQLAllocHandle分配描述器。

当应用程序调用API函数SQLAllocHandle时,驱动管理器或者ODBC驱动程序将为所声明的句柄类型分配内部结构,返回句柄值。

2.14异常处理

为了在程序开发过程中调试程序,发现程序错误,ODBC API通过两种方式返回有关ODBC API函数执行的的信息:返回码和诊断记录。返回码返回函数执行的返回值,说明函数执行成功与否。诊断记录说明函数执行的详细信息。


返回码(Return Code)

每一个ODBC API函数都返回一个代码——返回码,指示函数执行的成功与否。如果函数调用成功,返回码为SQL_SUCCESS或SQL_SUCCESS_WITH_INFO。SQL_SUCCESS指示可通过诊断记录获取有关操作的详细信息,SQL_SUCCESS_WITH_INFO指示应用程序执行结果带有警告信息,可通过诊断记录获取详细的信息。如果函数调用失败,返回码为SQL_ERROR。

下面的一段代码根据函数SQLFetch()执行的返回码,判断函数执行的成功与否,从而据此进行相应的处理。

 

SQLRETURN rtcode;

SQLHSTMT hstmt;

While(rtcode=SQLFetch(hstmt)!=SQL_NO_DATA)

{

if(rtcode==SQL_SUCCESS_WITH_INFO)

{

//显示警告信息

}

else

{

//显示出错信息

break;

}

//函数调用成功,进行处理

}

如果程序执行错误,返回码为SQL_INVALID_HANDLE,程序无法执行,而其它的返回码都带有程序执行的信息。


诊断记录(Diagnostic Records)

每个ODBC API函数都能够产生一系列的反映操作信息的诊断记录。这些诊断记录放在相关连的ODBC句柄中,直到下一个使用同一个句柄的函数调用,该诊断记录一直存在。诊断记录的大小没有限制。

诊断记录有两类:头记录(Head Record)和状态记录(Status Record)。头记录是第一版权法记录(Record 0),后面的记录为状态记录。诊断记录有许多的域组成,这些域在头记录和状态记录中是不同的。

可以用SQLGetDiagField函数获取诊断记录中的特定的域,另外,可以使用SQLGetDiagRec()获取诊断记录中一些常用的域,如SQLSTATE、原始错误号等。


头记录

头记录的各个域中包含了一个函数执行的通用信息,无论函数执行成功与否,只要不返回SQL_INVALID_HANDLE,都会生成头记录。


状态记录

状态记录中的每个域包含了驱动管理器、ODBC驱动程序或数据源返回的特定的错误或警告信息,包括SQLSTATE、原始错误码、诊断信息、列号和行号等。只有函数执行返回SQL_ERROR,SQL_STILL_EXEUTING、SQL_SUCCESS_WITH_INFO、SQL_NEED_DATA或SQL_NO_DATA时,才会生成诊断记录。


使用SQLGetDiagRec和SQLGetDiagField

应用程序可以调用函数SQLGetDiagRec或SQLGetDiagField获取诊断信息。对于给定的句柄,这两个函数返回最近使用该句柄的函数的诊断信息。当有使用该句柄的函数执行时,句柄记录所记录的原有的诊断信息被覆盖。如果函数执行后产生多个状态记录,程序必须多次调用这两个函数以获取信息。
 

2.2 应用ODBC API建立应用程序

虽然直接应用ODBC API编制应用程序相对来说较为繁琐,但是,由于直接使用ODBC API编写的程序相对要简洁、高效。所以,我们有必要学习直接使用ODBC API编程。

一般地,编写ODBC程序主要有以下几个步骤:


分配ODBC环境


分配连接句柄


连接数据源


构造和执行SQL语句


取得执行结果


断开同数据源的连接


释放ODBC环境

2.21 分配ODBC环境

对于任何ODBC应用程序来说,第一步的工作是装载驱动程序管理器,然后初始化ODBC环境,分配环境句柄。

首先,程序中声明一个SQLHENV类型的变量,然后调用函数SQLAllocHandle,向其中传递分配的上述SQLHENV类型的变量地址和SQL_HANDLE_ENV选项。如下代码所示:

SQLHENV henv;

SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv);

执行该调用语句后,驱动程序分配一个结构,该结构中存放环境信息,然后返回对应于该环境的环境句柄。

2.22分配连接句柄

分配环境句柄后,在建立至数据源的连接之前,我们必须分配一个连接句柄,每一个到数据源的连接对应于一个连接句柄。

首先,程序定义了一个SQLHDBC类型的变量,用于存放连接句柄,然后调用SQLAllocHandle函数分配句柄。如下代码所示:

SQLHDBC hdbc;

SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc);

henv为环境句柄。
 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.2 应用ODBC API建立应用程序

虽然直接应用ODBC API编制应用程序相对来说较为繁琐,但是,由于直接使用ODBC API编写的程序相对要简洁、高效。所以,我们有必要学习直接使用ODBC API编程。

一般地,编写ODBC程序主要有以下几个步骤:


分配ODBC环境


分配连接句柄


连接数据源


构造和执行SQL语句


取得执行结果


断开同数据源的连接


释放ODBC环境

2.21 分配ODBC环境

对于任何ODBC应用程序来说,第一步的工作是装载驱动程序管理器,然后初始化ODBC环境,分配环境句柄。

首先,程序中声明一个SQLHENV类型的变量,然后调用函数SQLAllocHandle,向其中传递分配的上述SQLHENV类型的变量地址和SQL_HANDLE_ENV选项。如下代码所示:

SQLHENV henv;

SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv);

执行该调用语句后,驱动程序分配一个结构,该结构中存放环境信息,然后返回对应于该环境的环境句柄。

2.22分配连接句柄

分配环境句柄后,在建立至数据源的连接之前,我们必须分配一个连接句柄,每一个到数据源的连接对应于一个连接句柄。

首先,程序定义了一个SQLHDBC类型的变量,用于存放连接句柄,然后调用SQLAllocHandle函数分配句柄。如下代码所示:

SQLHDBC hdbc;

SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc);

henv为环境句柄。
 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

1、 概述

1、1 Visual C++开发数据库技术的特点

Visual C++提供了多种多样的数据库访问技术——ODBC API、MFC ODBC、DAO、OLE DB、ADO等。这些技术各有自己的特点,它们提供了简单、灵活、访问速度快、可扩展性好的开发技术。


简单性

Visual C++中提供了MFC类库、ATL模板类以及AppWizard、ClassWizard等一系列的Wizard工具用于帮助用户快速的建立自己的应用程序,大大简化了应用程序的设计。使用这些技术,可以使开发者编写很少的代码或不需编写代码就可以开发一个数据库应用程序。


灵活性

Visual C++提供的开发环境可以使开发者根据自己的需要设计应用程序的界面和功能,而且,Visual C++提供了丰富的类库和方法,可以使开发者根据自己的应用特点进行选择。


访问速度快

为了解决ODBC开发的数据库应用程序访问数据库的速度慢的问题,Visual C++提供了新的访问技术——OLE DB和ADO,OLE DB和ADO都是基于COM接口的技术,使用这种技术可以直接对数据库的驱动程序进行访问,这大大提供了访问速度。


可扩展性

Visual C++提供了OLE技术和ActiveX技术,这种技术可以增强应用程序的能力。使用OLE技术和ActiveX技术可以使开发者利用Visual C++中提供的各种组件、控件以及第三方开发者提供的组件来创建自己的程序,从而实现应用程序的组件化。使用这种技术可以使应用程序具有良好的可扩展性。


访问不同种类数据源

传统的ODBC技术只能访问关系型数据库,在Visual C++中,提供了OLE DB访问技术,不仅可以访问关系型数据库,还可以访问非关系型数据库。

1、2 Visual C++开发数据库技术

Visual C++提供了多种访问数据库的技术,如下所示:


ODBC(Open DataBase Connectivity)


MFC ODBC(Microsoft Foundation Classes ODBC)


DAO (Data Access Object)


OLE DB(Object Link and Embedding DataBase)


ADO(ActiveX Data Object)

这些技术各有自己的特点,总结如下:


ODBC

ODBC是客户应用程序访问关系数据库时提供的一个统一的接口,对于不同的数据库,ODBC提供了一套统一的API,使应用程序可以应用所提供的API来访问任何提供了ODBC驱动程序的数据库。而且,ODBC已经成为一种标准,所以,目前所有的关系数据库都提供了ODBC驱动程序,这使ODBC的应用非常广泛,基本上可用于所有的关系数据库。

但由于ODBC只能用于关系数据库,使得利用ODBC很难访问对象数据库及其它非关系数据库。

由于ODBC是一种底层的访问技术,因些,ODBC API可以使客户应用程序能够从底层设置和控制数据库,完成一些高层数据库技术无法完成的功能。


MFC ODBC

由于直接使用ODBC API编写应用程序要编制大量代码,在Visual C++中提供了MFC ODBC类,封装了ODBC API,这使得利用MFC来创建ODBC的应用程序非常简便。


DAO

DAO提供了一种通过程序代码创建和操纵数据库的机制。多个DAO构成一个体系结构,在这个结构中,各个DAO对象协同工作。MFC DAO是微软提供的用于访问Microsoft Jet数据库文件(*.mdb)的强有力的数据库开发工具,它通过DAO的封装,向程序员提供了DAO丰富的操作数据库手段。


OLE DB

OLE DB是Visual C++开发数据库应用中提供的新技术,它基于COM接口。因此,OLE DB对所有的文件系统包括关系数据库和非关系数据库都提供了统一的接口。这些特性使得OLE DB技术比传统的数据库访问技术更加优越。

与ODBC技术相似,OLE DB属于数据库访问技术中的底层接口。

直接使用OLE DB来设计数据库应用程序需要大量的代码。在VC中提供了ATL模板,用于设计OLE DB数据应用程序和数据提供程序。


ADO

ADO技术是基于OLE DB的访问接口,它继承了OLE DB技术的优点,并且,ADO对OLE DB的接口作了封装,定义了ADO对象,使程序开发得到简化,ADO技术属于数据库访问的高层接口。

 

2、 使用ODBC API

Microsoft 开放数据库互连(ODBC,Open DataBase Connectivity)是Microsoft Windows 开放服务体系(WOSA)的一部分,是一个数据库访问的标准接口。使用这一标准接口,我们可以不关心具体的数据库管理系统(DBMS)的细节,而只要有相应类型数据库的ODBC驱动程序,就可以实现对数据库的访问。

ODBC编程接口为我们提供了极大的灵活性,我们可以通过这一个接口访问不同种类的数据库。而且,通过相应的ODBC驱动程序,我们可以方便地实现不同数据类型之间的转换。

2.1 ODBC API 概述

ODBC是一个应用广泛的数据库访问应用编程接口(API),使用标准的SQL(结构化查询语言)作为其数据库访问语言。

2.11体系结构

ODBC的结构是建立在客户机/服务器体系结构之上,它包含如下四个部分:

应用程序(Application ):

应用程序即用户的应用,它负责用户与用户接口之间的交互操作,以及调用ODBC函数以给出SQL请求并提取结果以及进行错误处理。

ODBC驱动程序管理器(Driver Manager):

ODBC驱动程序管理器为应用程序加载和调用驱动程序,它可以同时管理多个应用程序和多个驱动程序。它的功能是通过间接调用函数和使用动态链接库(DLL)来实现的,因此它一般包含在扩展名为”DLL”的文件中。

ODBC驱动程序(Driver)

ODBC 驱动程序执行ODBC函数调用,呈送 SQL 请求给指定的数据源,并将结果返回给应用程序。驱动程序也负责与任何访问数据源的必要软件层进行交互作用,这种层包括与底层网络或文件系统接口的软件。

数据源

数据源由数据集和与其相关联的环境组成,包括操作系统、DBMS 和网络(如果存在的话)。ODBC 通过引入“数据源”的概念解决了网络拓扑结构和主机的大范围差异问题,这样,用户看到的是数据源的名称而不必关心其它东西。

 

2.12数据类型

ODBC使用两类数据类型:SQL数据类型和C数据类型。SQL数据类型用于数据源,C数据类型用于应用程序代码中。

2.13句柄

ODBC API 实现数据库操作的手段是语句,这是一个强有力的手段。ODBC语句除了能执行SQL语句和完成查询操作之外,还能实现大多数数据库操作。

在ODBC中,使用不同的句柄(HANDLE)来标志环境(ENVIRONMENT)、连接(CONNECTION)、语句(STATEMENT)、描述器(DESCRIPTOR)等。

句柄就是一个应用程序变量,系统用它来存储关于应用程序的上下文信息和应用程序所用到的一些对象。它和 Windows 编程中的概念类似,不过ODBC 更加完善了句柄的作用。

1、 环境句柄是 ODBC 中整个上下文的句柄,使用 ODBC 的每个程序从创建环境句柄开始,以释放环境句柄结束。所有其它的句柄(这一应用程序所有的联接句柄和语句句柄)都由环境句柄中的上下文来管理。环境句柄在每个应用程序中只能创建一个。

2、联接句柄管理有关联接的所有信息。联接句柄可以分配多个,这不仅合法而且很有用;但不要生成不必要的句柄以免资源的浪费。但是,不同的驱动程序支持的联接情况有所不同,有的驱动程序在一个应用程序中仅支持一个联接句柄,有的驱动程序仅支持一个语句句柄。在应用程序中,可以在任何适当的时候联接或脱离数据源,但不要轻易地建立或脱离联接。

3、语句句柄是 ODBC API 真正发挥重要作用的,它被用来处理 SQL 语句及目录函数,每个语句句柄只与一个联接有关。当驱动程序接收一个来自应用程序的函数调用指令而该指令包含一个语句句柄时,驱动程序管理器将使用存储在语句句柄中的联接句柄来将这一函数调用发送给合适的驱动程序。

4、描述器句柄是元数据的集合,这些元数据描述了SQL语句的参数、记录集的列等信息。当有语句被分配内存之后,描述器自动生成,称为自动分配描述器。在程序中,应用程序也可调用SQLAllocHandle分配描述器。

当应用程序调用API函数SQLAllocHandle时,驱动管理器或者ODBC驱动程序将为所声明的句柄类型分配内部结构,返回句柄值。

2.14异常处理

为了在程序开发过程中调试程序,发现程序错误,ODBC API通过两种方式返回有关ODBC API函数执行的的信息:返回码和诊断记录。返回码返回函数执行的返回值,说明函数执行成功与否。诊断记录说明函数执行的详细信息。


返回码(Return Code)

每一个ODBC API函数都返回一个代码——返回码,指示函数执行的成功与否。如果函数调用成功,返回码为SQL_SUCCESS或SQL_SUCCESS_WITH_INFO。SQL_SUCCESS指示可通过诊断记录获取有关操作的详细信息,SQL_SUCCESS_WITH_INFO指示应用程序执行结果带有警告信息,可通过诊断记录获取详细的信息。如果函数调用失败,返回码为SQL_ERROR。

下面的一段代码根据函数SQLFetch()执行的返回码,判断函数执行的成功与否,从而据此进行相应的处理。

 

SQLRETURN rtcode;

SQLHSTMT hstmt;

While(rtcode=SQLFetch(hstmt)!=SQL_NO_DATA)

{

if(rtcode==SQL_SUCCESS_WITH_INFO)

{

//显示警告信息

}

else

{

//显示出错信息

break;

}

//函数调用成功,进行处理

}

如果程序执行错误,返回码为SQL_INVALID_HANDLE,程序无法执行,而其它的返回码都带有程序执行的信息。


诊断记录(Diagnostic Records)

每个ODBC API函数都能够产生一系列的反映操作信息的诊断记录。这些诊断记录放在相关连的ODBC句柄中,直到下一个使用同一个句柄的函数调用,该诊断记录一直存在。诊断记录的大小没有限制。

诊断记录有两类:头记录(Head Record)和状态记录(Status Record)。头记录是第一版权法记录(Record 0),后面的记录为状态记录。诊断记录有许多的域组成,这些域在头记录和状态记录中是不同的。

可以用SQLGetDiagField函数获取诊断记录中的特定的域,另外,可以使用SQLGetDiagRec()获取诊断记录中一些常用的域,如SQLSTATE、原始错误号等。


头记录

头记录的各个域中包含了一个函数执行的通用信息,无论函数执行成功与否,只要不返回SQL_INVALID_HANDLE,都会生成头记录。


状态记录

状态记录中的每个域包含了驱动管理器、ODBC驱动程序或数据源返回的特定的错误或警告信息,包括SQLSTATE、原始错误码、诊断信息、列号和行号等。只有函数执行返回SQL_ERROR,SQL_STILL_EXEUTING、SQL_SUCCESS_WITH_INFO、SQL_NEED_DATA或SQL_NO_DATA时,才会生成诊断记录。


使用SQLGetDiagRec和SQLGetDiagField

应用程序可以调用函数SQLGetDiagRec或SQLGetDiagField获取诊断信息。对于给定的句柄,这两个函数返回最近使用该句柄的函数的诊断信息。当有使用该句柄的函数执行时,句柄记录所记录的原有的诊断信息被覆盖。如果函数执行后产生多个状态记录,程序必须多次调用这两个函数以获取信息。
 

2.2 应用ODBC API建立应用程序

虽然直接应用ODBC API编制应用程序相对来说较为繁琐,但是,由于直接使用ODBC API编写的程序相对要简洁、高效。所以,我们有必要学习直接使用ODBC API编程。

一般地,编写ODBC程序主要有以下几个步骤:


分配ODBC环境


分配连接句柄


连接数据源


构造和执行SQL语句


取得执行结果


断开同数据源的连接


释放ODBC环境

2.21 分配ODBC环境

对于任何ODBC应用程序来说,第一步的工作是装载驱动程序管理器,然后初始化ODBC环境,分配环境句柄。

首先,程序中声明一个SQLHENV类型的变量,然后调用函数SQLAllocHandle,向其中传递分配的上述SQLHENV类型的变量地址和SQL_HANDLE_ENV选项。如下代码所示:

SQLHENV henv;

SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv);

执行该调用语句后,驱动程序分配一个结构,该结构中存放环境信息,然后返回对应于该环境的环境句柄。

2.22分配连接句柄

分配环境句柄后,在建立至数据源的连接之前,我们必须分配一个连接句柄,每一个到数据源的连接对应于一个连接句柄。

首先,程序定义了一个SQLHDBC类型的变量,用于存放连接句柄,然后调用SQLAllocHandle函数分配句柄。如下代码所示:

SQLHDBC hdbc;

SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc);

henv为环境句柄。
 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.2 应用ODBC API建立应用程序

虽然直接应用ODBC API编制应用程序相对来说较为繁琐,但是,由于直接使用ODBC API编写的程序相对要简洁、高效。所以,我们有必要学习直接使用ODBC API编程。

一般地,编写ODBC程序主要有以下几个步骤:


分配ODBC环境


分配连接句柄


连接数据源


构造和执行SQL语句


取得执行结果


断开同数据源的连接


释放ODBC环境

2.21 分配ODBC环境

对于任何ODBC应用程序来说,第一步的工作是装载驱动程序管理器,然后初始化ODBC环境,分配环境句柄。

首先,程序中声明一个SQLHENV类型的变量,然后调用函数SQLAllocHandle,向其中传递分配的上述SQLHENV类型的变量地址和SQL_HANDLE_ENV选项。如下代码所示:

SQLHENV henv;

SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv);

执行该调用语句后,驱动程序分配一个结构,该结构中存放环境信息,然后返回对应于该环境的环境句柄。

2.22分配连接句柄

分配环境句柄后,在建立至数据源的连接之前,我们必须分配一个连接句柄,每一个到数据源的连接对应于一个连接句柄。

首先,程序定义了一个SQLHDBC类型的变量,用于存放连接句柄,然后调用SQLAllocHandle函数分配句柄。如下代码所示:

SQLHDBC hdbc;

SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc);

henv为环境句柄。
 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.12数据类型

ODBC使用两类数据类型:SQL数据类型和C数据类型。SQL数据类型用于数据源,C数据类型用于应用程序代码中。

2.13句柄

ODBC API 实现数据库操作的手段是语句,这是一个强有力的手段。ODBC语句除了能执行SQL语句和完成查询操作之外,还能实现大多数数据库操作。

在ODBC中,使用不同的句柄(HANDLE)来标志环境(ENVIRONMENT)、连接(CONNECTION)、语句(STATEMENT)、描述器(DESCRIPTOR)等。

句柄就是一个应用程序变量,系统用它来存储关于应用程序的上下文信息和应用程序所用到的一些对象。它和 Windows 编程中的概念类似,不过ODBC 更加完善了句柄的作用。

1、 环境句柄是 ODBC 中整个上下文的句柄,使用 ODBC 的每个程序从创建环境句柄开始,以释放环境句柄结束。所有其它的句柄(这一应用程序所有的联接句柄和语句句柄)都由环境句柄中的上下文来管理。环境句柄在每个应用程序中只能创建一个。

2、联接句柄管理有关联接的所有信息。联接句柄可以分配多个,这不仅合法而且很有用;但不要生成不必要的句柄以免资源的浪费。但是,不同的驱动程序支持的联接情况有所不同,有的驱动程序在一个应用程序中仅支持一个联接句柄,有的驱动程序仅支持一个语句句柄。在应用程序中,可以在任何适当的时候联接或脱离数据源,但不要轻易地建立或脱离联接。

3、语句句柄是 ODBC API 真正发挥重要作用的,它被用来处理 SQL 语句及目录函数,每个语句句柄只与一个联接有关。当驱动程序接收一个来自应用程序的函数调用指令而该指令包含一个语句句柄时,驱动程序管理器将使用存储在语句句柄中的联接句柄来将这一函数调用发送给合适的驱动程序。

4、描述器句柄是元数据的集合,这些元数据描述了SQL语句的参数、记录集的列等信息。当有语句被分配内存之后,描述器自动生成,称为自动分配描述器。在程序中,应用程序也可调用SQLAllocHandle分配描述器。

当应用程序调用API函数SQLAllocHandle时,驱动管理器或者ODBC驱动程序将为所声明的句柄类型分配内部结构,返回句柄值。

2.14异常处理

为了在程序开发过程中调试程序,发现程序错误,ODBC API通过两种方式返回有关ODBC API函数执行的的信息:返回码和诊断记录。返回码返回函数执行的返回值,说明函数执行成功与否。诊断记录说明函数执行的详细信息。


返回码(Return Code)

每一个ODBC API函数都返回一个代码——返回码,指示函数执行的成功与否。如果函数调用成功,返回码为SQL_SUCCESS或SQL_SUCCESS_WITH_INFO。SQL_SUCCESS指示可通过诊断记录获取有关操作的详细信息,SQL_SUCCESS_WITH_INFO指示应用程序执行结果带有警告信息,可通过诊断记录获取详细的信息。如果函数调用失败,返回码为SQL_ERROR。

下面的一段代码根据函数SQLFetch()执行的返回码,判断函数执行的成功与否,从而据此进行相应的处理。

 

SQLRETURN rtcode;

SQLHSTMT hstmt;

While(rtcode=SQLFetch(hstmt)!=SQL_NO_DATA)

{

if(rtcode==SQL_SUCCESS_WITH_INFO)

{

//显示警告信息

}

else

{

//显示出错信息

break;

}

//函数调用成功,进行处理

}

如果程序执行错误,返回码为SQL_INVALID_HANDLE,程序无法执行,而其它的返回码都带有程序执行的信息。


诊断记录(Diagnostic Records)

每个ODBC API函数都能够产生一系列的反映操作信息的诊断记录。这些诊断记录放在相关连的ODBC句柄中,直到下一个使用同一个句柄的函数调用,该诊断记录一直存在。诊断记录的大小没有限制。

诊断记录有两类:头记录(Head Record)和状态记录(Status Record)。头记录是第一版权法记录(Record 0),后面的记录为状态记录。诊断记录有许多的域组成,这些域在头记录和状态记录中是不同的。

可以用SQLGetDiagField函数获取诊断记录中的特定的域,另外,可以使用SQLGetDiagRec()获取诊断记录中一些常用的域,如SQLSTATE、原始错误号等。


头记录

头记录的各个域中包含了一个函数执行的通用信息,无论函数执行成功与否,只要不返回SQL_INVALID_HANDLE,都会生成头记录。


状态记录

状态记录中的每个域包含了驱动管理器、ODBC驱动程序或数据源返回的特定的错误或警告信息,包括SQLSTATE、原始错误码、诊断信息、列号和行号等。只有函数执行返回SQL_ERROR,SQL_STILL_EXEUTING、SQL_SUCCESS_WITH_INFO、SQL_NEED_DATA或SQL_NO_DATA时,才会生成诊断记录。


使用SQLGetDiagRec和SQLGetDiagField

应用程序可以调用函数SQLGetDiagRec或SQLGetDiagField获取诊断信息。对于给定的句柄,这两个函数返回最近使用该句柄的函数的诊断信息。当有使用该句柄的函数执行时,句柄记录所记录的原有的诊断信息被覆盖。如果函数执行后产生多个状态记录,程序必须多次调用这两个函数以获取信息。
 

2.2 应用ODBC API建立应用程序

虽然直接应用ODBC API编制应用程序相对来说较为繁琐,但是,由于直接使用ODBC API编写的程序相对要简洁、高效。所以,我们有必要学习直接使用ODBC API编程。

一般地,编写ODBC程序主要有以下几个步骤:


分配ODBC环境


分配连接句柄


连接数据源


构造和执行SQL语句


取得执行结果


断开同数据源的连接


释放ODBC环境

2.21 分配ODBC环境

对于任何ODBC应用程序来说,第一步的工作是装载驱动程序管理器,然后初始化ODBC环境,分配环境句柄。

首先,程序中声明一个SQLHENV类型的变量,然后调用函数SQLAllocHandle,向其中传递分配的上述SQLHENV类型的变量地址和SQL_HANDLE_ENV选项。如下代码所示:

SQLHENV henv;

SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv);

执行该调用语句后,驱动程序分配一个结构,该结构中存放环境信息,然后返回对应于该环境的环境句柄。

2.22分配连接句柄

分配环境句柄后,在建立至数据源的连接之前,我们必须分配一个连接句柄,每一个到数据源的连接对应于一个连接句柄。

首先,程序定义了一个SQLHDBC类型的变量,用于存放连接句柄,然后调用SQLAllocHandle函数分配句柄。如下代码所示:

SQLHDBC hdbc;

SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc);

henv为环境句柄。
 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.2 应用ODBC API建立应用程序

虽然直接应用ODBC API编制应用程序相对来说较为繁琐,但是,由于直接使用ODBC API编写的程序相对要简洁、高效。所以,我们有必要学习直接使用ODBC API编程。

一般地,编写ODBC程序主要有以下几个步骤:


分配ODBC环境


分配连接句柄


连接数据源


构造和执行SQL语句


取得执行结果


断开同数据源的连接


释放ODBC环境

2.21 分配ODBC环境

对于任何ODBC应用程序来说,第一步的工作是装载驱动程序管理器,然后初始化ODBC环境,分配环境句柄。

首先,程序中声明一个SQLHENV类型的变量,然后调用函数SQLAllocHandle,向其中传递分配的上述SQLHENV类型的变量地址和SQL_HANDLE_ENV选项。如下代码所示:

SQLHENV henv;

SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv);

执行该调用语句后,驱动程序分配一个结构,该结构中存放环境信息,然后返回对应于该环境的环境句柄。

2.22分配连接句柄

分配环境句柄后,在建立至数据源的连接之前,我们必须分配一个连接句柄,每一个到数据源的连接对应于一个连接句柄。

首先,程序定义了一个SQLHDBC类型的变量,用于存放连接句柄,然后调用SQLAllocHandle函数分配句柄。如下代码所示:

SQLHDBC hdbc;

SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc);

henv为环境句柄。
 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2、 使用ODBC API

Microsoft 开放数据库互连(ODBC,Open DataBase Connectivity)是Microsoft Windows 开放服务体系(WOSA)的一部分,是一个数据库访问的标准接口。使用这一标准接口,我们可以不关心具体的数据库管理系统(DBMS)的细节,而只要有相应类型数据库的ODBC驱动程序,就可以实现对数据库的访问。

ODBC编程接口为我们提供了极大的灵活性,我们可以通过这一个接口访问不同种类的数据库。而且,通过相应的ODBC驱动程序,我们可以方便地实现不同数据类型之间的转换。

2.1 ODBC API 概述

ODBC是一个应用广泛的数据库访问应用编程接口(API),使用标准的SQL(结构化查询语言)作为其数据库访问语言。

2.11体系结构

ODBC的结构是建立在客户机/服务器体系结构之上,它包含如下四个部分:

应用程序(Application ):

应用程序即用户的应用,它负责用户与用户接口之间的交互操作,以及调用ODBC函数以给出SQL请求并提取结果以及进行错误处理。

ODBC驱动程序管理器(Driver Manager):

ODBC驱动程序管理器为应用程序加载和调用驱动程序,它可以同时管理多个应用程序和多个驱动程序。它的功能是通过间接调用函数和使用动态链接库(DLL)来实现的,因此它一般包含在扩展名为”DLL”的文件中。

ODBC驱动程序(Driver)

ODBC 驱动程序执行ODBC函数调用,呈送 SQL 请求给指定的数据源,并将结果返回给应用程序。驱动程序也负责与任何访问数据源的必要软件层进行交互作用,这种层包括与底层网络或文件系统接口的软件。

数据源

数据源由数据集和与其相关联的环境组成,包括操作系统、DBMS 和网络(如果存在的话)。ODBC 通过引入“数据源”的概念解决了网络拓扑结构和主机的大范围差异问题,这样,用户看到的是数据源的名称而不必关心其它东西。

 

2.12数据类型

ODBC使用两类数据类型:SQL数据类型和C数据类型。SQL数据类型用于数据源,C数据类型用于应用程序代码中。

2.13句柄

ODBC API 实现数据库操作的手段是语句,这是一个强有力的手段。ODBC语句除了能执行SQL语句和完成查询操作之外,还能实现大多数数据库操作。

在ODBC中,使用不同的句柄(HANDLE)来标志环境(ENVIRONMENT)、连接(CONNECTION)、语句(STATEMENT)、描述器(DESCRIPTOR)等。

句柄就是一个应用程序变量,系统用它来存储关于应用程序的上下文信息和应用程序所用到的一些对象。它和 Windows 编程中的概念类似,不过ODBC 更加完善了句柄的作用。

1、 环境句柄是 ODBC 中整个上下文的句柄,使用 ODBC 的每个程序从创建环境句柄开始,以释放环境句柄结束。所有其它的句柄(这一应用程序所有的联接句柄和语句句柄)都由环境句柄中的上下文来管理。环境句柄在每个应用程序中只能创建一个。

2、联接句柄管理有关联接的所有信息。联接句柄可以分配多个,这不仅合法而且很有用;但不要生成不必要的句柄以免资源的浪费。但是,不同的驱动程序支持的联接情况有所不同,有的驱动程序在一个应用程序中仅支持一个联接句柄,有的驱动程序仅支持一个语句句柄。在应用程序中,可以在任何适当的时候联接或脱离数据源,但不要轻易地建立或脱离联接。

3、语句句柄是 ODBC API 真正发挥重要作用的,它被用来处理 SQL 语句及目录函数,每个语句句柄只与一个联接有关。当驱动程序接收一个来自应用程序的函数调用指令而该指令包含一个语句句柄时,驱动程序管理器将使用存储在语句句柄中的联接句柄来将这一函数调用发送给合适的驱动程序。

4、描述器句柄是元数据的集合,这些元数据描述了SQL语句的参数、记录集的列等信息。当有语句被分配内存之后,描述器自动生成,称为自动分配描述器。在程序中,应用程序也可调用SQLAllocHandle分配描述器。

当应用程序调用API函数SQLAllocHandle时,驱动管理器或者ODBC驱动程序将为所声明的句柄类型分配内部结构,返回句柄值。

2.14异常处理

为了在程序开发过程中调试程序,发现程序错误,ODBC API通过两种方式返回有关ODBC API函数执行的的信息:返回码和诊断记录。返回码返回函数执行的返回值,说明函数执行成功与否。诊断记录说明函数执行的详细信息。


返回码(Return Code)

每一个ODBC API函数都返回一个代码——返回码,指示函数执行的成功与否。如果函数调用成功,返回码为SQL_SUCCESS或SQL_SUCCESS_WITH_INFO。SQL_SUCCESS指示可通过诊断记录获取有关操作的详细信息,SQL_SUCCESS_WITH_INFO指示应用程序执行结果带有警告信息,可通过诊断记录获取详细的信息。如果函数调用失败,返回码为SQL_ERROR。

下面的一段代码根据函数SQLFetch()执行的返回码,判断函数执行的成功与否,从而据此进行相应的处理。

 

SQLRETURN rtcode;

SQLHSTMT hstmt;

While(rtcode=SQLFetch(hstmt)!=SQL_NO_DATA)

{

if(rtcode==SQL_SUCCESS_WITH_INFO)

{

//显示警告信息

}

else

{

//显示出错信息

break;

}

//函数调用成功,进行处理

}

如果程序执行错误,返回码为SQL_INVALID_HANDLE,程序无法执行,而其它的返回码都带有程序执行的信息。


诊断记录(Diagnostic Records)

每个ODBC API函数都能够产生一系列的反映操作信息的诊断记录。这些诊断记录放在相关连的ODBC句柄中,直到下一个使用同一个句柄的函数调用,该诊断记录一直存在。诊断记录的大小没有限制。

诊断记录有两类:头记录(Head Record)和状态记录(Status Record)。头记录是第一版权法记录(Record 0),后面的记录为状态记录。诊断记录有许多的域组成,这些域在头记录和状态记录中是不同的。

可以用SQLGetDiagField函数获取诊断记录中的特定的域,另外,可以使用SQLGetDiagRec()获取诊断记录中一些常用的域,如SQLSTATE、原始错误号等。


头记录

头记录的各个域中包含了一个函数执行的通用信息,无论函数执行成功与否,只要不返回SQL_INVALID_HANDLE,都会生成头记录。


状态记录

状态记录中的每个域包含了驱动管理器、ODBC驱动程序或数据源返回的特定的错误或警告信息,包括SQLSTATE、原始错误码、诊断信息、列号和行号等。只有函数执行返回SQL_ERROR,SQL_STILL_EXEUTING、SQL_SUCCESS_WITH_INFO、SQL_NEED_DATA或SQL_NO_DATA时,才会生成诊断记录。


使用SQLGetDiagRec和SQLGetDiagField

应用程序可以调用函数SQLGetDiagRec或SQLGetDiagField获取诊断信息。对于给定的句柄,这两个函数返回最近使用该句柄的函数的诊断信息。当有使用该句柄的函数执行时,句柄记录所记录的原有的诊断信息被覆盖。如果函数执行后产生多个状态记录,程序必须多次调用这两个函数以获取信息。
 

2.2 应用ODBC API建立应用程序

虽然直接应用ODBC API编制应用程序相对来说较为繁琐,但是,由于直接使用ODBC API编写的程序相对要简洁、高效。所以,我们有必要学习直接使用ODBC API编程。

一般地,编写ODBC程序主要有以下几个步骤:


分配ODBC环境


分配连接句柄


连接数据源


构造和执行SQL语句


取得执行结果


断开同数据源的连接


释放ODBC环境

2.21 分配ODBC环境

对于任何ODBC应用程序来说,第一步的工作是装载驱动程序管理器,然后初始化ODBC环境,分配环境句柄。

首先,程序中声明一个SQLHENV类型的变量,然后调用函数SQLAllocHandle,向其中传递分配的上述SQLHENV类型的变量地址和SQL_HANDLE_ENV选项。如下代码所示:

SQLHENV henv;

SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv);

执行该调用语句后,驱动程序分配一个结构,该结构中存放环境信息,然后返回对应于该环境的环境句柄。

2.22分配连接句柄

分配环境句柄后,在建立至数据源的连接之前,我们必须分配一个连接句柄,每一个到数据源的连接对应于一个连接句柄。

首先,程序定义了一个SQLHDBC类型的变量,用于存放连接句柄,然后调用SQLAllocHandle函数分配句柄。如下代码所示:

SQLHDBC hdbc;

SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc);

henv为环境句柄。
 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.2 应用ODBC API建立应用程序

虽然直接应用ODBC API编制应用程序相对来说较为繁琐,但是,由于直接使用ODBC API编写的程序相对要简洁、高效。所以,我们有必要学习直接使用ODBC API编程。

一般地,编写ODBC程序主要有以下几个步骤:


分配ODBC环境


分配连接句柄


连接数据源


构造和执行SQL语句


取得执行结果


断开同数据源的连接


释放ODBC环境

2.21 分配ODBC环境

对于任何ODBC应用程序来说,第一步的工作是装载驱动程序管理器,然后初始化ODBC环境,分配环境句柄。

首先,程序中声明一个SQLHENV类型的变量,然后调用函数SQLAllocHandle,向其中传递分配的上述SQLHENV类型的变量地址和SQL_HANDLE_ENV选项。如下代码所示:

SQLHENV henv;

SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv);

执行该调用语句后,驱动程序分配一个结构,该结构中存放环境信息,然后返回对应于该环境的环境句柄。

2.22分配连接句柄

分配环境句柄后,在建立至数据源的连接之前,我们必须分配一个连接句柄,每一个到数据源的连接对应于一个连接句柄。

首先,程序定义了一个SQLHDBC类型的变量,用于存放连接句柄,然后调用SQLAllocHandle函数分配句柄。如下代码所示:

SQLHDBC hdbc;

SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc);

henv为环境句柄。
 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.12数据类型

ODBC使用两类数据类型:SQL数据类型和C数据类型。SQL数据类型用于数据源,C数据类型用于应用程序代码中。

2.13句柄

ODBC API 实现数据库操作的手段是语句,这是一个强有力的手段。ODBC语句除了能执行SQL语句和完成查询操作之外,还能实现大多数数据库操作。

在ODBC中,使用不同的句柄(HANDLE)来标志环境(ENVIRONMENT)、连接(CONNECTION)、语句(STATEMENT)、描述器(DESCRIPTOR)等。

句柄就是一个应用程序变量,系统用它来存储关于应用程序的上下文信息和应用程序所用到的一些对象。它和 Windows 编程中的概念类似,不过ODBC 更加完善了句柄的作用。

1、 环境句柄是 ODBC 中整个上下文的句柄,使用 ODBC 的每个程序从创建环境句柄开始,以释放环境句柄结束。所有其它的句柄(这一应用程序所有的联接句柄和语句句柄)都由环境句柄中的上下文来管理。环境句柄在每个应用程序中只能创建一个。

2、联接句柄管理有关联接的所有信息。联接句柄可以分配多个,这不仅合法而且很有用;但不要生成不必要的句柄以免资源的浪费。但是,不同的驱动程序支持的联接情况有所不同,有的驱动程序在一个应用程序中仅支持一个联接句柄,有的驱动程序仅支持一个语句句柄。在应用程序中,可以在任何适当的时候联接或脱离数据源,但不要轻易地建立或脱离联接。

3、语句句柄是 ODBC API 真正发挥重要作用的,它被用来处理 SQL 语句及目录函数,每个语句句柄只与一个联接有关。当驱动程序接收一个来自应用程序的函数调用指令而该指令包含一个语句句柄时,驱动程序管理器将使用存储在语句句柄中的联接句柄来将这一函数调用发送给合适的驱动程序。

4、描述器句柄是元数据的集合,这些元数据描述了SQL语句的参数、记录集的列等信息。当有语句被分配内存之后,描述器自动生成,称为自动分配描述器。在程序中,应用程序也可调用SQLAllocHandle分配描述器。

当应用程序调用API函数SQLAllocHandle时,驱动管理器或者ODBC驱动程序将为所声明的句柄类型分配内部结构,返回句柄值。

2.14异常处理

为了在程序开发过程中调试程序,发现程序错误,ODBC API通过两种方式返回有关ODBC API函数执行的的信息:返回码和诊断记录。返回码返回函数执行的返回值,说明函数执行成功与否。诊断记录说明函数执行的详细信息。


返回码(Return Code)

每一个ODBC API函数都返回一个代码——返回码,指示函数执行的成功与否。如果函数调用成功,返回码为SQL_SUCCESS或SQL_SUCCESS_WITH_INFO。SQL_SUCCESS指示可通过诊断记录获取有关操作的详细信息,SQL_SUCCESS_WITH_INFO指示应用程序执行结果带有警告信息,可通过诊断记录获取详细的信息。如果函数调用失败,返回码为SQL_ERROR。

下面的一段代码根据函数SQLFetch()执行的返回码,判断函数执行的成功与否,从而据此进行相应的处理。

 

SQLRETURN rtcode;

SQLHSTMT hstmt;

While(rtcode=SQLFetch(hstmt)!=SQL_NO_DATA)

{

if(rtcode==SQL_SUCCESS_WITH_INFO)

{

//显示警告信息

}

else

{

//显示出错信息

break;

}

//函数调用成功,进行处理

}

如果程序执行错误,返回码为SQL_INVALID_HANDLE,程序无法执行,而其它的返回码都带有程序执行的信息。


诊断记录(Diagnostic Records)

每个ODBC API函数都能够产生一系列的反映操作信息的诊断记录。这些诊断记录放在相关连的ODBC句柄中,直到下一个使用同一个句柄的函数调用,该诊断记录一直存在。诊断记录的大小没有限制。

诊断记录有两类:头记录(Head Record)和状态记录(Status Record)。头记录是第一版权法记录(Record 0),后面的记录为状态记录。诊断记录有许多的域组成,这些域在头记录和状态记录中是不同的。

可以用SQLGetDiagField函数获取诊断记录中的特定的域,另外,可以使用SQLGetDiagRec()获取诊断记录中一些常用的域,如SQLSTATE、原始错误号等。


头记录

头记录的各个域中包含了一个函数执行的通用信息,无论函数执行成功与否,只要不返回SQL_INVALID_HANDLE,都会生成头记录。


状态记录

状态记录中的每个域包含了驱动管理器、ODBC驱动程序或数据源返回的特定的错误或警告信息,包括SQLSTATE、原始错误码、诊断信息、列号和行号等。只有函数执行返回SQL_ERROR,SQL_STILL_EXEUTING、SQL_SUCCESS_WITH_INFO、SQL_NEED_DATA或SQL_NO_DATA时,才会生成诊断记录。


使用SQLGetDiagRec和SQLGetDiagField

应用程序可以调用函数SQLGetDiagRec或SQLGetDiagField获取诊断信息。对于给定的句柄,这两个函数返回最近使用该句柄的函数的诊断信息。当有使用该句柄的函数执行时,句柄记录所记录的原有的诊断信息被覆盖。如果函数执行后产生多个状态记录,程序必须多次调用这两个函数以获取信息。
 

2.2 应用ODBC API建立应用程序

虽然直接应用ODBC API编制应用程序相对来说较为繁琐,但是,由于直接使用ODBC API编写的程序相对要简洁、高效。所以,我们有必要学习直接使用ODBC API编程。

一般地,编写ODBC程序主要有以下几个步骤:


分配ODBC环境


分配连接句柄


连接数据源


构造和执行SQL语句


取得执行结果


断开同数据源的连接


释放ODBC环境

2.21 分配ODBC环境

对于任何ODBC应用程序来说,第一步的工作是装载驱动程序管理器,然后初始化ODBC环境,分配环境句柄。

首先,程序中声明一个SQLHENV类型的变量,然后调用函数SQLAllocHandle,向其中传递分配的上述SQLHENV类型的变量地址和SQL_HANDLE_ENV选项。如下代码所示:

SQLHENV henv;

SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv);

执行该调用语句后,驱动程序分配一个结构,该结构中存放环境信息,然后返回对应于该环境的环境句柄。

2.22分配连接句柄

分配环境句柄后,在建立至数据源的连接之前,我们必须分配一个连接句柄,每一个到数据源的连接对应于一个连接句柄。

首先,程序定义了一个SQLHDBC类型的变量,用于存放连接句柄,然后调用SQLAllocHandle函数分配句柄。如下代码所示:

SQLHDBC hdbc;

SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc);

henv为环境句柄。
 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.2 应用ODBC API建立应用程序

虽然直接应用ODBC API编制应用程序相对来说较为繁琐,但是,由于直接使用ODBC API编写的程序相对要简洁、高效。所以,我们有必要学习直接使用ODBC API编程。

一般地,编写ODBC程序主要有以下几个步骤:


分配ODBC环境


分配连接句柄


连接数据源


构造和执行SQL语句


取得执行结果


断开同数据源的连接


释放ODBC环境

2.21 分配ODBC环境

对于任何ODBC应用程序来说,第一步的工作是装载驱动程序管理器,然后初始化ODBC环境,分配环境句柄。

首先,程序中声明一个SQLHENV类型的变量,然后调用函数SQLAllocHandle,向其中传递分配的上述SQLHENV类型的变量地址和SQL_HANDLE_ENV选项。如下代码所示:

SQLHENV henv;

SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv);

执行该调用语句后,驱动程序分配一个结构,该结构中存放环境信息,然后返回对应于该环境的环境句柄。

2.22分配连接句柄

分配环境句柄后,在建立至数据源的连接之前,我们必须分配一个连接句柄,每一个到数据源的连接对应于一个连接句柄。

首先,程序定义了一个SQLHDBC类型的变量,用于存放连接句柄,然后调用SQLAllocHandle函数分配句柄。如下代码所示:

SQLHDBC hdbc;

SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc);

henv为环境句柄。
 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

2.23 连接数据源

当连接句柄分配完成后,我们可以设置连接属性,所有的连接属性都有缺省值,但是我们可以通过调用函数SQLSetConnectAttr()来设置连接属性。用函数SQLGetConnectAttr()获取这些连接属性。

函数格式如下:


SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);

SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
 


应用程序可以根据自己的需要设置不同的连接属性。

完成对连接属性的设置之后,就可以建立到数据源的连接了。对于不同的程序和用户接口,可以用不同的函数建立连接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。

SQLConnect

该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。

函数格式:


SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);


参数:

ConnectionHandle 连接句柄

ServerName 数据源名称

NameLength1 数据源名称长度

UserName 用户ID

NameLength2 用户ID长度

Authentication 用户口令

NameLength3 用户口令长度

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码演示了如何使用ODBC API的SQLConnect函数建立同数据源SQLServer的连接。 


#include “sqlext.h”

SQLHENV henv;;

SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

/*Allocate environment handle */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the ODBC version environment attribute */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate connection handle */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set login timeout to 5 seconds. */

SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);

/* Connect to data source */

retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,

(SQLCHAR*) "JohnS", SQL_NTS,

(SQLCHAR*) "Sesame", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate statement handle */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data */;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

}

SQLDisconnect(hdbc);

}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);

}

}

SQLFreeHandle(SQL_HANDLE_ENV, henv);

SQLDriveConnect
 


函数SQLDriveConnect用一个连接字符串建立至数据源的连接。它可以提供比SQLConnect函数的三个参数更多的信息,可以让用户输入必要的连接信息。

如果连接建立,该函数返回完整的字符串,应用程序可使用该连接字符串建立另外的连接。

函数格式:


SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);


参数:

ConnectionHandle 连接句柄

WindowHandle 窗口句柄,应用程序可以用父窗口的句柄,或用NULL指针

InConnectionString 连接字符串长度

OutConnectionString 一个指向连接字符中的指针

BufferLength 存放连接字符串的缓冲区的长度

StringLength2Ptr 返回的连接字符串中的字符数

DriverCompletion 额外连接信息,可能取值有:SQL_DRIVER_PROMPT,

SQL_DRIVER_COMPLETE,

SQL_DRIVER_COMPLETE_REQUIRED, or

SQL_DRIVER_NOPROMPT.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLBrowseConnect

函数SQLBrowseConnect支持以一种迭代的方式获取到数据源的连接,直到最后建立连接。它是基于客房机/服务器的体系结构,因此,本地数据库不支持该函数。

一般,我们提供部分连接信息,如果足以建立到数据源的连接,则成功建立连接,否则返回SQL__NEED__DATA,并在OutConnectionString参数中返回所需要的信息。

函数格式:


SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);


参数:

ConnectionHandle 连接句柄

InConnectionString 指向输出字符串的指针

StringLength1 输出字符串的指针长度

OutConnectionString 指向输出字符串的指针

BufferLength 用于存放输出字符串的缓冲区的长度

StringLength2Ptr 实际返回的字符串的长度 

返回值:


SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.


成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

下面的代码讲述了如何使用ODBC API的SQLBrowseConnect函数建立同数据源的连接。 


#define BRWS_LEN 100SQLHENV

henv;SQLHDBC hdbc;

SQLHSTMT hstmt;

SQLRETURN retcode;

SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];

SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Set the version environment attribute. */

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Allocate the connection handle. */

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Call SQLBrowseConnect until it returns a value other than */

/* SQL_NEED_DATA (pass the data source name the first time). */

/* If SQL_NEED_DATA is returned, call GetUserInput (not */

/* shown) to build a dialog from the values in szConnStrOut. */

/* The user-supplied values are returned in szConnStrIn, */

/* which is passed in the next call to SQLBrowseConnect. */

lstrcpy(szConnStrIn, "DSN=Sales"); do {

retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,

szConnStrOut, BRWS_LEN, &cbConnStrOut);

if (retcode == SQL_NEED_DATA)

GetUserInput(szConnStrOut, szConnStrIn);

} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

/* Allocate the statement handle. */

retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Process data after successful connection */ ...;

SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }

SQLDisconnect(hdbc); } }

SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}

SQLFreeHandle(SQL_HANDLE_ENV, henv);
 

 

 
2.24 SQL操作

构造和执行SQL语句

构造SQL语句

可以通过三种方式构造SQL语句:在程序开发阶段确定、在运行时确定或由用户输入SQL语句。

在程序开发时确定的SQL语句,具有易于实现、且可在程序编码时进行测试的优势。

在程序运行时确定SQL语句提供了极大灵活性,但给程序高度带来了困难,且需更多的处理时间。由用户输入的SQL语句,极大的增强了程序的功能,但是,程序必须提供友好的人机界面,且对用户输入的语句执行一定程序的语法检查,能够报告用户错误。

执行SQL语句

应用程序的绝大部分数据库访问工作都是通过执行SQL语句完成的,在执行SQL语句之前,必须要先分配一个语句句柄,然后设置相应语句的语句属性,再执行SQL语句。当一个语句句柄使用完成后,调用函数SQLFreeHandle()释放该句柄。


SQLExecute()

SQLExecute用于执行一个准备好的语然,当语句中有参数时,用当前绑定的参数变量的值。

函数格式:

SQLRETURN SQLExecute(SQLHSTMT StatementHandle);

参数:

StatementHandle 标识执行SQL语句的句柄,可以用SQLAllocHandle()来获得。

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NEED_DATA, SQL_STILL_EXECUTING, SQL_ERROR, SQL_NO_DATA, or SQL_INVALID_HANDLE

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 


SQLExecDiret()

SQLExecDirect直接执行SQL语句,对于只执行一次的操作来说,该函数是速度最快的方法。

函数格式:

SQLRETURN SQLExecDirect(SQLHSTMT StatementHandle,SQLCHAR *StatementText,SQLINTEGER TextLength);

参数:

StatementHandle 语句句柄

StatementText 要执行的SQL语然

StatementText SQL语句的长度。

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NEED_DATA, SQL_STILL_EXECUTING, SQL_ERROR, SQL_NO_DATA, or SQL_INVALID_HANDLE

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 


SQLPripare()

对于需多次执行的SQL语句来说,除了使用SQLExecDirect函数之外,我们也可以在执行SQL语句之前,先准备SQL语句的执行。对于使用参数的语句,这可大提高程序执行速度。

函数格式:

SQLRETURN SQLPrepare(SQLHSTMT StatementHandle,SQLCHAR* StatementText,SQLINTEGER TextLength);

参数:

StatementHandle 语句句柄

StatementText 要执行的SQL语然

StatementText SQL语句的长度。

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NEED_DATA, SQL_STILL_EXECUTING, SQL_ERROR, SQL_NO_DATA, or SQL_INVALID_HANDLE

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

使用参数

使用参数可以使一条SQL语句多次执行,得到不同结果

SQLBindParameter

函数SQLBindParameter负责为参数定义变量,实现参数值的传递。

函数格式如下:

SQLRETURNSQLBindParameter(SQLHSTMT StatementHandle,SQLUSMALLINT ParameterNumber,SQLSMALLINT InputOutputType,SQLSMALLINT ValueType,SQLSMALLINT ParameterType,SQLUINTEGER ColumnSize,SQLSMALLINT DecimalDigits,SQLPOINTER ParameterValuePtr,SQLINTEGER BufferLength,SQLINTEGER *StrLen_or_IndPtr);

参数:

StatementHandle 语句句柄

ParameterNumber 绑定的参数在SQL语句中的序号,在SQL中,所有参数从左到右顺序编号,从1开始。SQL语句执行之前,应该为每个参数调用函数SQLBindParameter绑定到某个程序变量。

InputOutputType 参数类型,可为SQL_PARA_INPUT, SQL_PARAM_INPUT_OUTPUT, SQL_PARAM_OUTPUT。

ParameterType 参数数据类型

ColumnSIze 参数大小

DecimalDigits 参数精度

ParameterValutePtr 指向程序中存放参数值的缓冲区的指针

BufferLength 程序中存放参数值的缓冲区的字节数

StrLen_or_IndPtr 指向存放参数ParameterValuePtr的缓冲区指针

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。

执行时传递参数

对于某些文本文档或位图文件,要占用大量的存储空间。因此,在数据源传递这些数据时,可以分开传递。有两个函数可完成这个工作。

函数格式:

SQLRETURN SQLPutData(SQLHSTMT StatementHandle,

SQLPOINTER DataPtr,SQLINTEGER StrLen_or_Ind);

参数:

StatementHandle 参数句柄

DataPtr 指向包含实际数据的缓冲区指针。

StrLen_or_Lnd 缓冲区长度

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。

函数格式:

SQLRETURNSQLParamData(SQLHSTMT StatementHandle,SQLPOINTER *ValuePtrPtr);

参数:

StatementHandle 参数句柄

ValuePtrPtr 指向缓冲区地址的指针

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。  

下面的代码展示如何使用这两个函数

#define MAX_DATA_LEN 1024

SQLINTEGER cbPartID = 0, cbPhotoParam, cbData;

SQLUINTEGER sPartID; szPhotoFile;

SQLPOINTER pToken, InitValue;

SQLCHAR Data[MAX_DATA_LEN];

SQLRETURN retcode;

SQLHSTMT hstmt;

retcode = SQLPrepare(hstmt, "INSERT INTO PICTURES (PARTID, PICTURE) VALUES

(?, ?)", SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Bind the parameters. For parameter 2, pass */

/* the parameter number in ParameterValuePtr instead of a buffer */

/* address. */ SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_ULONG,

SQL_INTEGER, 0, 0, &sPartID, 0, &cbPartID);

SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT,

SQL_C_BINARY, SQL_LONGVARBINARY,

0, 0, (SQLPOINTER) 2, 0, &cbPhotoParam);

/* Set values so data for parameter 2 will be */

/* passed at execution. Note that the length parameter in */

/* the macro SQL_LEN_DATA_AT_EXEC is 0. This assumes that */

/* the driver returns "N" for the SQL_NEED_LONG_DATA_LEN */

/* information type in SQLGetInfo. */

cbPhotoParam = SQL_LEN_DATA_AT_EXEC(0);

sPartID = GetNextID(); /* Get next available employee ID */

/* number. */ retcode = SQLExecute(hstmt);

/* For data-at-execution parameters, call SQLParamData to */

/* get the parameter number set by SQLBindParameter. */

/* Call InitUserData. Call GetUserData and SQLPutData */

/* repeatedly to get and put all data for the parameter. */

/* Call SQLParamData to finish processing this parameter */

while (retcode == SQL_NEED_DATA) {

retcode = SQLParamData(hstmt, &pToken);

if (retcode == SQL_NEED_DATA) {

InitUserData((SQLSMALLINT)pToken, InitValue);

while (GetUserData(InitValue, (SQLSMALLINT)pToken, Data,

&cbData))

SQLPutData(hstmt, Data, cbData); } }}

VOID InitUserData(sParam, InitValue)SQLPOINTER InitValue;{

SQLCHAR szPhotoFile[MAX_FILE_NAME_LEN];

/* Prompt user for bitmap file containing employee */

/* photo. OpenPhotoFile opens the file and returns the */ /* file handle. */

PromptPhotoFileName(szPhotoFile);

OpenPhotoFile(szPhotoFile, (FILE *)InitValue); break; }

BOOL GetUserData(InitValue, sParam, Data, cbData)SQLPOINTER InitValue;

SQLCHAR *Data;SQLINTEGER *cbData;BOOL Done;{

/* GetNextPhotoData returns the next piece of photo */

/* data and the number of bytes of data returned */

/* (up to MAX_DATA_LEN). */ Done = GetNextPhotoData((FILE *)InitValue, Data,

MAX_DATA_LEN, &cbData); if (Done) {

ClosePhotoFile((FILE *)InitValue);

return (TRUE); }

return (FALSE); }
 

 
记录的添加、删除和更新

应用程序对数据源的数据更新可以通过三种方式实现:使用相应的SQL语句在数据源上执行;调用函数SQLSetPos实现记录集的定义更新;调用函数SQLBulkOperations实现数据的更新。

直接在数据源上执行SQL语句的方式,可以适用于任何的ODBC数据源,但是,对于后两种更新方式,有的数据源并不支持,应用程序可以调用函数SQLGetInfo确定数据源是否支持这两种方式。


定位更新和删除

要使用定位更新和删除功能,要按如下顺序:

1)取回记录集:

2)定位到要进行更新或删除操作的行

3)执行更新或删除操作 

参考如下的代码:

#define ROWS 20#define STATUS_LEN 6

SQLCHAR szStatus[ROWS][STATUS_LEN], szReply[3];

SQLINTEGER cbStatus[ROWS], cbOrderID;

SQLUSMALLINT rgfRowStatus[ROWS];

SQLUINTEGER sOrderID, crow = ROWS, irow;

SQLHSTMT hstmtS, hstmtU;

SQLSetStmtAttr(hstmtS, SQL_ATTR_CONCURRENCY, (SQLPOINTER) SQL_CONCUR_ROWVER, 0);

SQLSetStmtAttr(hstmtS, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) SQL_CURSOR_KEYSET_DRIVEN, 0);

SQLSetStmtAttr(hstmtS, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER) ROWS, 0);

SQLSetStmtAttr(hstmtS, SQL_ATTR_ROW_STATUS_PTR, (SQLPOINTER) rgfRowStatus, 0);

SQLSetCursorName(hstmtS, "C1", SQL_NTS);

SQLExecDirect(hstmtS, "SELECT ORDERID, STATUS FROM ORDERS ", SQL_NTS);

SQLBindCol(hstmtS, 1, SQL_C_ULONG, &sOrderID, 0, &cbOrderID);

SQLBindCol(hstmtS, 2, SQL_C_CHAR, szStatus, STATUS_LEN, &cbStatus);

while ((retcode == SQLFetchScroll(hstmtS, SQL_FETCH_NEXT, 0)) != SQL_ERROR) {

if (retcode == SQL_NO_DATA_FOUND) break;

for (irow = 0; irow < crow; irow++) {

if (rgfRowStatus[irow] != SQL_ROW_DELETED)

printf("%2d %5d %*s/n", irow+1, sOrderID, NAME_LEN-1, szStatus[irow]);

} while (TRUE) { printf("/nRow number to update?");

gets(szReply); irow = atoi(szReply);

if (irow > 0 && irow <= crow) { printf("/nNew status?");

gets(szStatus[irow-1]);

SQLSetPos(hstmtS, irow, SQL_POSITION, SQL_LOCK_NO_CHANGE);

SQLPrepare(hstmtU,

"UPDATE ORDERS SET STATUS=? WHERE CURRENT OF C1", SQL_NTS);

SQLBindParameter(hstmtU, 1, SQL_PARAM_INPUT,

SQL_C_CHAR, SQL_CHAR,

STATUS_LEN, 0, szStatus[irow], 0, NULL);

SQLExecute(hstmtU); } else if (irow == 0) { break; }

}

}
 


用SQLBulkOperations()更新数据

函数SQLBulkOperations的操作是基于当前行集的,在调用函数SQLBulkOperations之前,必须先调用函数SQLFetch或SQLFetchScroll获取行集,然后,再执行修改或删除操作。 

函数格式:

SQLRETURN SQLBulkOperations(SQLHSTMT StatementHandle,

SQLUSMALLINT Operation); 
 

参数:

StatementHandle 参数句柄

Operation 标识执行的操作类型,可以是以下几种之一:

SQL_ADD

SQL_UPDATE_BY_BOOKMARK

SQL_DELETE_BY_BOOKMARK

SQL_FETCH_BY_BOOKMARK 

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NEED_DATA, SQL_STILL_EXECUTING, SQL_ERROR, or SQL_INVALID_HANDLE
 

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

取回查询结果

绑定列

从数据源取回的数据存放在应用程序定义的变量中,因此,我们必须首先分配与记录集中字段相对应的变量,然后通过函数SQLBindCol将记录字段同程序变量绑定在一起。对于长记录字段,可以通过调用函数SQLGetData()直接取回数据。

绑定字段可以根据自己的需要,全部绑定,也可以绑定其中的某几个字段。

记录集中的字段可以在任何时候绑定,但是,新的绑定只有当下一次从数据源中取数据时执行的操作才有郊,而不会对已经取回的数据产生影响。

函数格式:

SQLRETURN SQLBindCol(SQLHSTMT StatementHandle,

SQLUSMALLINTColumnNumber, SQLSMALLINT TargetType,

SQLPOINTERTargetValuePtr,SQLINTEGERBufferLength,

SQLINTEGER *StrLen_or_IndPtr);
 

参数:

StatementHandle 语句句柄

ColumnNumber 标识要绑定的列号。数据列号从0开始升序排列,其中第0列用作书签。如果没有使用书签,则列号从1开始。

TargetType 数据类型

TargetValuePtr 绑定到数据字段的缓冲区的地址

BufferLength 缓冲区长度

StrLen_or_IndPtr 指向绑定数据列使用的长度的指针.

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。 

SQLFetch()

函数SQLFetch用于将记录集中的下一行变为当前行,并把所有捆绑过的数据字段的数据拷贝到相应的缓冲区。

函数格式:

SQLRETURN SQLFetch(SQLHSTMT StatementHandle)

参数:

StatementHandle 语句句柄

返回值:

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NO_DATA, SQL_STILL_EXECUTING, SQL_ERROR, or SQL_INVALID_HANDLE.

成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。

光标

应用程序获取数据是通过光标(Cursor)来实现的,在ODBC中,主要有三种类型的光标:


单向光标:

单向光标只能向前移动,要返回记录集的开始位置,程序必须先关闭光标,再打开光标,它对于只需要浏览一次的应用非常有用,而且效率很高。对于需要光标前后移动的,单向光村不适用。


可滚动光标

可滚动光标通常基于图形用户界面的程序,用户通过屏幕向前或向后滚动,浏览记录集中的数据。


块光标

所谓块光标,可以理解为执行多行的光标,它所指向的行称为行集。对于网络环境下的应用,使用块光标可以在一定程序上减轻网络负载。

要使用块光标,应完成以下工作:

1)设定行集大小

2)绑定行集缓冲区

3)设定语句句柄属性

4)取行行集结果

由于块光标返回多行记录,应用程序必须把这多行的数据绑定到某些数据组中,这些数据称为行集缓冲区。绑定方式有两种:列方式和行方式。


ODBC光标库

有些应用程序不支持可滚动光标和块光标,ODBC SDK 提供了一个光标库(ODBCCR32.DLL),在应用程序中可通过设置连接属性(SQL_STTR_ODBC_CURSORS)激活光标库。 

参考如下代码:

#define NAME_LEN 50

#define PHONE_LEN 10

SQLCHAR szName[NAME_LEN], szPhone[PHONE_LEN];

SQLINTEGER sCustID, cbName, cbCustID, cbPhone;

SQLHSTMT hstmt;

SQLRETURN retcode;retcode = SQLExecDirect(hstmt,

"SELECT CUSTID, NAME, PHONE FROM CUSTOMERS ORDER BY 2, 1, 3",

SQL_NTS);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

/* Bind columns 1, 2, and 3 */

SQLBindCol(hstmt, 1, SQL_C_ULONG, &sCustID, 0, &cbCustID);

SQLBindCol(hstmt, 2, SQL_C_CHAR, szName, NAME_LEN, &cbName);

SQLBindCol(hstmt, 3, SQL_C_CHAR, szPhone, PHONE_LEN, &cbPhone);

/* Fetch and print each row of data. On */

/* an error, display a message and exit. */ while (TRUE) {

retcode = SQLFetch(hstmt);

if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) {

show_error(); }

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

fprintf(out, "%-*s %-5d %*s", NAME_LEN-1, szName,

sCustID, PHONE_LEN-1, szPhone); } else { break; }

}

}
 

2.25 断开同数据源的连接

当完成对数据库操作后,就可以调用SQLDisconnect函数关闭同数据源连接。

当该句柄的事务操作还未完成时,应用程序调用SQLDisconnect,这时,驱动器返回SQLSTATE 25000,表明此次事务没有变化且连接还打开。

在应用程序调用SQLDisconnect之前没有释放与之相连的描述时,当成功的与数据源断开连接后,驱动器自动释放与之相连的参数、描述器等。但当与之相连的某一个参数还在执行异步操作时,SQLDisConnect返回SQL_ERROR,且SQLSTATE的值置为HY010.

2.26 释放ODBC环境

最后一步就是释放ODBC环境参数了。

2.3 ODBC API编程总结

关系数据库的研究与应用是当今计算机界最活跃的领域之一,各种数据库产品行行色色,各有千秋;这种情况一方面给用户带来了好处,另一方面又给应用程序的移植带来了困难。尤其是在客户机/服务器体系结构中,当用户要从客户机端访问不同的服务器,而这些服务器的数据库系统又各不相同,数据库之间的互连访问就成为一个难题,因此,微软公司提出了ODBC。由于ODBC思想上的先进性及其微软公司的开放策略,ODBC现在已经成为事实上的工业标准,它是目前数据库应用方面很多问题强有力的解决方案,正逐步成为Windows平台上的标准接口。

ODBC是一种用来在相关或不相关的数据库管理系统(DBMS)中存取数据的标准应用程序设计接口(API)。它的基本思想是为用户提供简单、标准、透明、统一的数据库联接的公共编程接口,在各个厂家的支持下能为用户提供一致的应用开发界面,使应用程序独立于数据库产品,实现各种数据库之间的通信。开发厂商根据ODBC的标准去实现底层的驱动程序,它对用户是透明的。

作为一种数据库联接的标准技术,ODBC有以下几个主要特点:

1·ODBC是一种使用SQL的程序设计接口;

2·ODBC的设计是建立在客户机/服务器体系结构基础之上的;

3·ODBC使应用程序开发者避免了与数据源联接的复杂性;

4·ODBC的结构允许多个应用程序访问多个数据源,即应用程序与数据源的关系是多对多的关系。 
 

3、 使用MFC访问ODBC数据源

3.1 概述

VisualC++的MFC类库定义了几个数据库类。在利用ODBC编程时,经常要使用到CDatabase(数据库类),CRecordSet(记录集类)和CRecordView(可视记录集类)。 其中:

CDatabase类对象提供了对数据源的连接,通过它你可以对数据源进行操作。

CRecordView类对象能以控制的形式 显示数据库记录。这个视图是直接连到一个CRecordSet对象的表视图。

CRecordSet类对象提供了从数据源 中提取出的记录集。CRecordSet对象通常用于两种形式: 动态行集(dynasets)和快照集(snapshots)。动态行集能保 持与其他用户所做的更改保持同步。快照集则是数据的一个静态视图。每一种形式在记录集被打开时都提供一组记录,所不同的是,当你在一个动态行集里滚 动到一条记录时,由其他用户或是你应用程序中的其他记录集对该记录所做的更改会相应地显示出来。 

Visual C++提供了几种记录集,可以用来定制应用程序的工作方式。查看这些不同选项的最快方式要兼顾速度和特征。你会发现,在很多情况下,如果想添加特征,就必须付出程序执行速度降低的代价。下面告诉你一些可以自由支配的记录集选项。更重要的是,要告诉你从这个选项可以获得更快的速度还是更多的特征。

1、Snapshot(快照) 这个选项要Visual C++在一次快照中下载整个查询。换言之,及时快速地给数据库内容拍照,并把它作为未来工作的基础。这种方法有三个缺点。第一,你看不到别人在网络上做的更新,这可能意味着你的决定是建立在老信息的基础上。第二,一次就下载所有这些记录,这意味着在下载期间给网络增加了沉重的负担。第三,记录下载时用户会结束等待,这意味着网络的呼叫性能变得更低。然而这种方法也有两个优点。第一,记录一旦被下载,该工作站所需的网络活动几乎就没有了棗这为其它请求释放了带宽。总之,你会看到网络的吞吐量增大了。第二,因为所有被申请的记录都在用户的机器上,所以用户实际上会得到应用程序更佳的总体性能。你可能想把快照的方法限制在较小的数据库上使用,原因在于快照适用于用户请求信息而不适用于数据编辑会话。

2、Dynaset(动态集) 使用这个选项时,Visual C++创建指向所请求的每个记录的实际指针。另外,只有填充屏幕时实际需要的记录是从服务器上下载来的。这种方法的好处很明显。几乎马上就能在屏幕上看到记录。而且还会看到其它用户对数据库所做的更改。最后,其它用户也会看到你做的更改,因为动态集在你更改记录时被上载到服务器上。很明显,这种方法要求对服务器的实时访问,它减小了网络总吞吐量并降低了应用程序的性能。这个选项适合于创建用户要花费很多时间来编辑数据的应用程序。同时,它也是大型数据库的最佳选择,原因在于只需下载用户实际需要的信息。

3.2 应用ODBC编程

可以应用AppWizard来建立一个ODBC的应用程序框架,也可以直接使用ODBC来进行数据库编程,这时,应包括头文件afxdb.h。

应用ODBC编程两个最重要的类是CDatabase和CRecordSet,但在应用程序中,不应直接使用CRecordSet类,而必须从CRecordSet类产生一个导出类,并添加相应于数据库表中字段的成员变量。随后,重载CRecordset类的成员函数DoFieldExchange,该函数通过使用RFX函数完成数据库字段与记录集域数据成员变量的数据交换,RFX函数同对话框数据交换(DDX)机制相类似,负责完成数据库与成员变量间的数据交换。 

下面举例说明在VisualC++环境中ODBC 的编程技巧:

3.21 数据库连接

在CRecordSet类中定义了一个成员变 量m_pDatabase:

CDatabase *m_pDatabase;

它是指向对象数据库类的指针。如果在CRecordSet类对象调用Open()函数之前,将一个已经打开的CDatabase类对象指针传给m_pDatabase,就能共享相同 的CDatabase类对象。如: 


CDatabase m_db;

CRecordSet m_set1,m_set2;

m_db.Open(_T("Super_ES")); // 建 立ODBC 连 接

m_set1.m_pDatabase=&m_db; //m_set1 复 用m_db 对 象

m_set2.m_pDatabse=&m_db; // m_set2 复 用m_db 对 象

或如下:


Cdatabase db;

db.Open(“Database”); //建立ODBC连接

CrecordSet m_set(&db); //构造记录集对象,使数据库指向db
 

 

3、 使用MFC访问ODBC数据源

3.1 概述

VisualC++的MFC类库定义了几个数据库类。在利用ODBC编程时,经常要使用到CDatabase(数据库类),CRecordSet(记录集类)和CRecordView(可视记录集类)。 其中:

你可能感兴趣的:(c++)