嵌入式SQL实验.docx
- 文档编号:18401095
- 上传时间:2023-08-16
- 格式:DOCX
- 页数:38
- 大小:311.20KB
嵌入式SQL实验.docx
《嵌入式SQL实验.docx》由会员分享,可在线阅读,更多相关《嵌入式SQL实验.docx(38页珍藏版)》请在冰点文库上搜索。
嵌入式SQL实验
实验4嵌入式SQL和ODBC的使用
实验目的
1.熟悉ODBC的配置和使用
2.熟悉嵌入式SQL编程
3.巩固SQL的知识
实验平台
1.OS:
WindowsXP
2.DBMS:
SQLServer2000
3.Compiler:
VisualC++6.0
预备知识
1)嵌入式SQL编程:
嵌入式SQL由SQL语句和C/C++代码组成。
其中SQL语句由预处理器翻译成C或C++的源代码。
对预处理后的源代码进行编译、连接生成可执行程序后方可运行。
●SQL预处理器
SQLServer的预处理程序是nsqlprep.exe。
其常用的语法格式如下:
nsqlprep程序文档名
⏹nsqlprep详细的语法格式以及参数意义,请看联机帮助。
经查阅联机帮助,nsqlprep的语法格式如下:
nsqlprepprogram_file_name[/SQLACCESS|/NOSQLACCESS]
[/FLAGGER{ENTRY|NONE}][/DB[server_name.]database_name
/PASS{login[.password]|$INTEGRATED}][/BINDfile_name]
[/MSGfile_name][/NOLOGO][/PLANname][/NOLINES]
[/user_defined_option]
⏹要求程序文档名的后缀为.sqc,可以省略。
⏹预编译后得到的文档,与程序文档同名,后缀为.c;放在与程序文档名同一个路径下
nsqlprep.exe在SQLServer的安装目录的MSSQL\Binn下。
在本机中SQLServer的安装目录是C:
\ProgramFiles\MicrosoftSQLServer,nsqlprep.exe在C:
\ProgramFiles\MicrosoftSQLServer\MSSQL\Binn。
由于默认的安装方式(典型安装)并没有安装应用程序nsqlprep.exe,因此,需要把本机中E:
\院内学习工作\大三\数据库\SQLServer2000个人版\x86\binn目录下的内容拷贝到该目录下。
●连接方式
经预处理后的c文件就可以用c的编译器进行编译连接了。
使用VisualC++6.0进行编译连接,连接方式是动态连接,用到动态链接库SQLakw32.dll,sqlaiw32.dll;此两文件已经随同binn.rar的其他内容,被拷贝到C:
\ProgramFiles\MicrosoftSQLServer\MSSQL\Binn下;但仍然需要把该路径加到系统的路径变量中,以使得程序运行时能找到这两个文件。
方法1:
把该两文件拷贝到操作系统目录下的子目录system32中
方法2:
把C:
\ProgramFiles\MicrosoftSQLServer\MSSQL\Binn加到系统环境变量path中。
“我的电脑”->“属性”->“高级”->“环境变量”->“path,编辑”,如下图所示:
在变量值中加入该路径值;注意,路径间用分号”;”分开。
在实验过程中发现如果只做第二步,在之后的运行过程中会报错,只有将方法一也执行了这个连接的准备工作才算是正式完成。
2)通过ODBC访问数据库:
配置ODBC,为SQLServer添加数据源。
如下图所示:
初始化环境:
1.SQLServer2000为其嵌入式SQL提供了一些特殊的接口;默认的安装方式(典型安装)并没有安装这些接口;因此,需要把devtools.rar解压到SQLServer的系统目录下(注意,不是安装目录);本机是把操作系统安装在C盘,则SQLServer的系统目录则是C:
\ProgramFiles\MicrosoftSQLServer。
2.初始化SQLServer的预编译环境。
⏹初始化VisualC++6.0编译器环境,运行文件:
\MicrosoftVisualStudio\VC98\Bin\VCVARS32.BAT
这个过程要在DOS下运行才有效,即找vcvars32.bat的路径,在DOS下运行。
具体步骤如下:
⏹初始化SQLServer的预编译环境,运行文件:
\devtools\samples\esqlc\setenv.bat。
运行方式与vcvars32.bat相同,结果如下:
3.初始化VisualC++6.0环境。
⏹Tools->options->directories->Include
Files:
C:
\ProgramFiles\MicrosoftSQLServer\devtools\include
⏹Tools->options->directories->Lib
Files:
C:
\ProgramFiles\MicrosoftSQLServer\devtools\x86lib
注意:
这些路径需要设为第一项。
如下图所示:
⏹Project->Settings->Link->Object/LibraryModules,添加库文件:
SQLakw32.lib,Caw32.lib
注意,两个文件之间用空格分开。
以上部分均在上机课上在师姐的指导下完成。
实验活动
1.阅读和分析程序esql.sqc,解释程序的主要内容和主要数据结构。
程序的主要内容:
嵌入式SQL的使用,将SQL嵌入到C语言中,在SQL的数据库中通过SELECT语句获取数据,并将获得的信息通过主变量传递给主语言并打印输出。
给出的程序中将程序连接到WXF的SQL服务器上的pubs数据库上,查询满足以下SELECT语句的数据信息:
selectEmployeeIDfromorderswhereOrderID=345
查询得到的结果由主变量EmployeeID传给主语言(C语言),C语言得到数据信息后打印输出。
程序分为以下几块:
1)主变量的声明:
在EXECSQLBEGINDECLARESECTION;和EXECSQLENDDECLARESECTION;之间声明主变量EmployeeID。
2)连接到DBMS:
连接到数据库的管理系统以便从中查询登陆的数据库。
连接到数据库的语法为:
EXECSQLCONNECTTOSQLServer.DataBaseNameUSERlogName.passwd
3)查错:
为了更好的判断和查找错误以修改程序,所以在每次执行完SQL语句后都应该对sqlca所返回的状态值加以判断。
若sqlcode等于0,则输出建立成功信息,否则报错。
4)执行查询:
在这里嵌入SQL的查询语句EXECSQLselectEmployeeIDINTO:
EmployeeIDfromorderswhereOrderID=345,并通过主变量EmployeeID返回查询到的结果,打印结果。
5)断开所有连接:
执行完所有的数据库的访问后,断开所有的连接以释放系统资源。
语法为:
EXECSQLDISCONNECTALL;
数据结构:
主要为在数据库中存储的表,及针对表进行的查找。
2.对程序esql.sqc作适当的修改,使之可以在本地系统上可以运行。
进行预处理、编译、连接(lib连接),查看运行结果。
1)修改:
只需要对连接的服务器及数据库进行修改即可:
EXECSQLCONNECTTOSKY.pubsUSERabc.abc;
同时由于pubs数据库中没有orders表,所以对SELECT语句也作了修改如下:
EXECSQLselectemp_idINTO:
EmployeeIDfromemployeewherelname='Accorti';
2)进行预处理:
将esql.sqc文件放在C:
\ProgramFiles\MicrosoftSQLServer\MSSQL\Binn目录下,运行cmd,进入C:
\ProgramFiles\MicrosoftSQLServer\MSSQL\Binn目录,用nsqlprepesql.sqc的方式运行该文件,可以在C:
\ProgramFiles\MicrosoftSQLServer\MSSQL\Binn中找到预编译后生成的.c文件。
运行过程显示如下:
3)连接操作已经在前面的初始化环境过程中完成。
运行结果如下:
不知为什么,在黄伟的机子上运行时,不管怎么换查询条件,结果总是0
但是在田超的机子上运行的时候,就能够得出正确结果。
田超查询的是Northwind数据库中的orders表,语句为EXECSQLselectEmployeeIDINTO:
EmployeeIDfromorderswhereOrderID=10248;
运行结果如下:
经反复实验,首先排除了黄伟机子的问题,因为在田超的机器上运行也是0。
于是又开始怀疑是数据库的问题。
首先在程序中打印出了sqlcode,如图:
看到sqlcode<0,说明这个语句没有被执行。
开始以为是用户没有访问数据库的权限的问题,但是发现把用户改成sa,把默认数据库改为pubs依然存在这个问题。
将田超的sqc文件和黄伟的放在一起比较,最终发现原来是因为pubs数据库中emp_id的数据类型是empid,而在c中定义的主变量是int型,两者类型不匹配,造成了错误。
黄伟机子上的正确结果:
4)出现的怪异问题:
尽管之前的准备步骤都已经全部做完,但是在预编译时总是会出现以下问题,
每次都要重新把安装文件下的BIN和DEVTOOLS重新拷一遍到C盘SQLSERVER相应得路径下,然后再在DOS下运行setenv.bat和vcvars32.bat两个文件才能解决这个问题,有时甚至所有步骤都要重新做一次。
不明白这是什么原因。
我们在网上查到.bat格式的文件是批处理文件,它在日常的应用中可以发挥巨大的作用,但批处理命令执行的效率比较低,而且不小心会把里面的命令破坏掉。
所以不知是不是因为.bat的稳定性不好。
思考:
●sqlca结构中主要的数据项有哪些?
我们常用的有哪些?
sqlca是一个含有错误变量和状态指示符的数据结构。
通过检查sqlca,应用程序能够检查出嵌入式SQL语句是否成功,并根据成功与否决定是否继续往下执行。
与编译器自动在嵌入SQL语句中包含SQLCA数据结构。
从联机帮助上我们可以找到,SQLCA结构中主要的数据项如下(用结构体表示):
在SQLCA中我们经常用到的是sqlcode,它用来记录最近执行的SQL状态:
"0":
表示该SQL语句被正确执行,无错误发生
>0:
表示执行了该语句,但遇到了错误
<0:
表示由于数据库、系统、网络或应用程序错误等等原因未执行该语句
●SQL操作的常见的错误类型有哪些?
如何得到错误信息?
举例说明
SQL中常见的错误类型有:
通过下面的这些返回值,可以得到相应的出错信息。
例子是我们上面黄伟机子上出现的问题,当时sqlcode返回值为-10039,我觉得它代表的应该是类型不匹配的错误,但不知道为什么,在下面这张表(联机丛书)里查不到这个值
Messagenumber
Runtime/
compiletime
Description
-4998
C
Attempttoconnecttothespecifieddatabaseserverfailed.
-19031
C
Unabletoopenbindfile.
-19051
C
Toomanysections.
-19101
R
Statementtoolong.
-19103
R
Illegal%svalue%s.
Nonnumeric%svalue%s.
(Invalidnumberforthetime-outvalue.)
-19104
R/C
IncorrectSQLstatementsyntax.
-19199
C
ESQLkeyword(s)detectedinPREPAREstatement.
-19306
C
Hostvariableusedbutnotdeclared.
-19313
R
Toofewhostvariables.
-19324
C
Hostvariablemaynotbeusedinthiscontext.
-19408
R
InvalidSQLdatatypeforSQL_TYP_DECIMAL.
-19413
R
Dataoverflowoccurredduringdecimaldataconversion.
-19422
R
UnknownSQLServerdatatype.
-19423
R
Invaliddestinationdatatype.
-19501
R
Nocursordeclared.
-19505
C
Duplicatecursorname:
%s.
-19508
R
Cursornotpositionedonarow.
-19514
R
Cursornotprepared.
-19517
R
Cursoropenattemptedfornon-SELECTpreparedstatement.
-19521
R
Opencursorfailureforsection%dofplans.
-19523
R
Failuretolocate/closecursor.Section%d,plan%s.
-19524
R
Tableforthiscursornotupdatable.
-19525
R
Attempttofetchonunopenedcursor.
-19526
R
Noaccessplanforthiscursor.
-19527
R
Couldnotgetsectionforthiscursor.
-19528
R
Connectionforsection%dofplan%shasNULLDBPROCESS.
-19701
R
NULLconnectionname.
Connection%snotfound.
-19702
R
Connectionnamenotfound.
Attempttoclosenonexistentconnection.
-19703
R
FailedtogetDBPROCESS.
Autoconnectfailure.
-19706
R
Loginfailureinsection%d.
-19707
R
Duplicateconnectionname.
-19822
R
ImproperlyinitializeduserSQLDA.
-19911
C
TheSQLdatatypespecifiedforahostvariableisinvalid.
-19913
C
Thetokenidentifierhasalreadybeenused.
-19917
C
Invalidorincorrectoptiontosqlainit().
-19946
C
Cursor%snotdeclared.
-19953
C
Invalidcalltype.
-19955
R
Textnotfoundin%ssection%u.
-19956
R
Accessplansectionorstatementtextnotfound.
-19957
R
Accessplanorstatementtextnotfound.
-19994
R
CannotrunnextBEGINDECLAREsections.Statementignored.
-19995
R
ENDDECLAREencounteredwithoutprecedingBEGINDECLAREstatement.Statementignored.
-19999
C
Aninternalerroroccurred.
连接DBMS错误
通过sqlca中的变量sqlcode的返回值获得错误信息,当返回值为0时,表示连接成功,否则,连接失败。
例如esql.sqc中用以下语句获得错误信息:
if(SQLCODE==0)
{
printf("ConnectiontoSQLServerestablished\n");
}
else
{
//连接DBMS错误
printf("ERROR:
ConnectiontoSQLServerfailed\n");
return
(1);
}
●如何处理SQL操作的错误信息?
a)对于DBMS连接错误:
检查连接是否正常:
1)看SQL服务器是否启动
2)所连接的数据库是否存在
3)登录用户是否具备相应的权限(登录用户的数据库角色)
4)网络连接端口(1433)是否打开
b)用sqlcode:
在程序的error段输入如下语句:
error:
printf("错误%d\n",SQLCODE);
根据sqlcode的值查看联机帮助,根据在联机帮助上查到的错误信息检查相应的SQL语句,针对性的进行修改,直到其能正确运行
c)WHENEVER语句:
在每条嵌入式SQL语句之后立即编写一条检查SQLCODE值的程序是一件很繁琐的事情,为了简化错误处理,可以使用WHENEVER语句:
WHENEVER是说明语句,不是可执行语句,不返回SQLCODE,只是根据SQLCA中的返回码指定相应的措施。
它通知预编译程序在每条可执行嵌入式SQL语句之后自动生成错误处理程序,并指定了错误处理操作。
用户可以使用WHENEVER语句通知预编译程序去如何处理三种异常处理:
lWHENEVERSQLERRORaction:
表示一旦sql语句执行时遇到错误信息,则执行action,action中包含了处理错误的代码(SQLCODE<0)。
lWHENEVERSQLWARNINGaction:
表示一旦sql语句执行时遇到警告信息,则执行aciton,即action中包含了处理警报的代码(SQLCODE=1)。
lWHENEVERNOTFOUND:
表示一旦sql语句执行时没有找到相应的元组,则执行action,即action包含了处理没有查到内容的代码(SQLCODE=100)。
针对上述三种异常处理,用户可以指定预编译程序采取以下三种行为(action):
lWHENEVER…GOTO:
通知预编译程序产生一条转移语句。
lWHENEVER…CONTINUE:
取消先前的WHENEVER语句的作用,通知预编译程序让程序的控制流转入到下一个主语言语句。
lWHENEVER…CALL:
通知预编译程序调用函数。
例如:
EXECSQLWHENEVERSQLERRORGOTOer1
EXECSQLINSERTINTOstudentVALUES(‘s1’,..)
EXECSQLINSERTINTOstudentVALUES(‘s2’,..)
经过预编译后会转换为以下语句:
EXECSQLINSERTINTOstudentVALUES(‘s1’,..)
If(sqlca.sqlcode<0)gotoer1;
EXECSQLINSERTINTOstudentVALUES(‘s2’,..)
If(sqlca.sqlcode<0)gotoer1;
出错处理函数如下:
voidhSQLError(char*msg)
{
printf("\n%s,%ld,%s\n",msg,sqlca.sqlcode,(char*)sqlca.sqlerrm.sqlerrmc);
EXECSQLROLLBACKRELEASE;
exit(-1);
}
●如何断开连接,并释放资源清除环境?
建议尝试程序esql.sqc的方法以外的别的方法。
释放资源清除环境:
EXECSQLCOMMITWORKRELEASE;
断开连接:
EXECSQLDISCONNECTALL;//断开所有连接
EXECSQLDISCONNECTconnection_name;//如果在连接时定义了连接名,则可通过断开连接名来断开连接
(如定义了EXECSQLCONNECTTOSKY.pubsASMyconnectionUSERsa.sa;就可以通过EXECSQLDISCONNECTMyconnection断开和数据库pubs的连接,此语句对和其他数据库的连接无效)
EXECSQLDISCONNECTCURRENT;//表示断开当前连接
3.阅读和分析程序odbc.cpp,解释程序的主要内容和主要数据结构。
程序的主要内容:
在连接到的数据源上查询sno=’s1’的sname和city.
程序主要分为以下几块:
以下为程序开始部分:
1)定义retcode,henv,hdbc,hstmt四个变量,分别对应错误返回码,环境句柄,数据库连接句柄,语句句柄;
2)用SQLAllocHandle分配环境变量,同时用SQLSetEnvAttr告诉odbc这是一个odbc3.0的应用程序;
3)用SQLAllocHandle分配连接句柄;
4)用SQLConnect连接数据库;
以下为程序主体部分:
5)使用SQLAllocHandle分配语句句柄;
6)用SQLExecDirect或别的语句执行表的创建,查询,及修改;
7)用SQLBindCol把某个结果属性列绑定到变量上,用SQLFetch获取查询信息;或是用SQLFetch和SQLGetData来获取查询信息。
以下为程序结束部分,释放所有句柄和环境空间:
8)用SQLFreeHandle释放语句句柄;
9)用SQLDisconnect断开连接;
10)用SQLFreeHandle释放连接句柄
11)用SQLFreeHandle释放环境句柄
心得:
在程序中申请三个句柄的过程是环环相扣的,系统在分配句柄的过程中要用到以前句柄的参数。
而在释放句柄的时候,是要按照申请句柄的逆序来逐一释放的。
程序的主要数据结构:
我认为是三个句柄以及在处理结果的时候SQLBindCol(或SQLGetData)函数所开辟的缓冲区。
4.对程序odbc.cpp作适当的修改,使之可以在本地系统上可以运行。
进行编译、连接,查看运行结果。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 嵌入式 SQL 实验
![提示](https://static.bingdoc.com/images/bang_tan.gif)