📄 esql-c资料(完全版)二_unix_操作系统_网络学院_天新网.htm
字号:
3) { <BR>strcpy (userid, argv[1]);<BR>strcpy (passwd,
argv[2]);<BR>EXEC SQL CONNECT TO sample USER :userid USING :passwd;
(3)<BR>CHECKERR ("CONNECT TO SAMPLE");<BR>}<BR>else {<BR>printf
("\nUSAGE: static [userid passwd]\n\n");<BR>return 1;<BR>} /* endif
*/<BR><BR>EXEC SQL SELECT FIRSTNME INTO :firstname <BR>FROM
employee<BR>WHERE LASTNAME = 'JOHNSON';(4)<BR>CHECKERR ("SELECT
statement"); (5)<BR>printf( "First name = %s\n", firstname
);<BR>EXEC SQL CONNECT RESET; (6)<BR>CHECKERR ("CONNECT
RESET");<BR>return 0;<BR>}<BR>/* end of program : STATIC.SQC */
<P>上面是一个简单的静态嵌入SQL语句的应用程序。它包括了静态嵌入SQL的主要部分。<BR>(1)中的include
SQLCA语句定义并描述了SQLCA的结构。SQLCA用于应用程序和数据库之间的通讯,其中的SQLCODE返回SQL语句执行后的结果状态。<BR>(2)在BEGIN
DECLARE SECTION和END DECLARE
SECTION之间定义了主变量。主变量可被SQL语句引用,也可以被C语言语句引用。它用于将程序中的数据通过SQL语句传给数据库管理器,或从数据库管理器接收查询的结果。在SQL语句中,主变量前均有“:”标志以示区别。<BR>(3)在每次访问数据库之前必须做CONNECT操作,以连接到某一个数据库上。这时,应该保证数据库实例已经启动。<BR>(4)是一条选择语句。它将表employee中的LASTNAME为“JOHNSON”的行数据的FIRSTNAME查出,并将它放在firstname变量中。该语句返回一个结果。可以通过游标返回多个结果。<BR>(5)在该程序中通过调用宏CHECKERR(即调用函数check_error)来返回SQL语句执行的结果。Check_error函数在下面讲解。<BR>(6)最后断开数据库的连接。<BR>从上例看出,每条嵌入式SQL语句都用EXEC
SQL开始,表明它是一条SQL语句。这也是告诉预编译器在EXEC
SQL和“;”之间是嵌入SQL语句。如果一条嵌入式SQL语句占用多行,在C程序中可以用续行符“\”。<BR>3.2
嵌入SQL语句<BR>3.2.1宿主变量<BR>1)、声明方法<BR>宿主变量就是在嵌入式SQL语句中引用主语言说明的程序变量(如上例中的firstname变量)。如:<BR>………….<BR>EXEC
SQL SELECT FIRSTNME INTO :firstname (4)<BR>FROM employee<BR>WHERE
LASTNAME = 'JOHNSON';<BR>………….<BR>在嵌入式SQL语句中使用宿主变量前,必须采用BEGIN
DECLARE SECTION 和END DECLARE
SECTION之间给宿主变量说明。这两条语句不是可执行语句,而是预编译程序的说明。宿主变量是标准的C程序变量。嵌入SQL语句使用宿主变量把数据库中查询到的值返回给应用程序(称为输出宿主变量),也用于将程序中给定的值传到SQL语句中(称为输入宿主变量)。显然,C程序和嵌入SQL语句都可以访问宿主变量。<BR>在使用宿主变量前,请注意以下几点:<BR>l宿主变量的长度不能超过30字节。开始的字母不能是EXEC和SQL。<BR>l宿主变量必须在被引用之前定义。<BR>l一个源程序文件中可以有多个SQL说明段。<BR>l宿主变量名在整个程序中必须是唯一的。<BR>2)、宿主变量的数据类型<BR>宿主变量是一个用程序<A
href="http://school.21tx.com/photo/"
target=_blank>设计</A>语言的数据类型说明并用程序设计语言处理的程序变量;另外,在嵌入SQL语句中用宿主变量保存数据库数据。所以,在嵌入SQL语句中,必须映射C数据类型为合适的DB2数据类型。必须慎重选择宿主变量的数据类型。请看下面这个例子:<BR>EXEC
SQL BEGIN DECLARE SECTION;<BR>short hostvar1 = 39;<BR>char *hostvar2
= "telescope";<BR>EXEC SQL END DECLARE SECTION;
<P>EXEC SQL UPDATE inventory<BR>SET department = :hostvar1<BR>WHERE
part_num = "4572-3";
<P>EXEC SQL UPDATE inventory<BR>SET prod_descrip =
:hostvar2<BR>WHERE part_num =
"4572-3";<BR>在第一个update语句中,department列为smallint数据类型,所以应该把hostvar1定义为short数据类型。这样的话,从C到DB2的hostvar1可以直接映射。在第二个update语句中,prod_descip列为varchar数据类型,所以应该把hostvar2定义为字符数组。这样的话,从C到DB2的hostvar2可以从字符数组映射为varchar数据类型。<BR>下表列出了C的数据类型和DB2的数据类型的一些转换关系:<BR>DB2数据类型C数据类型<BR>Smallintshort<BR>IntegerLong<BR>Decimal(p,s)无<BR>DoubleDouble<BR>DateChar[11]<BR>TimeChar[9]<BR>TimestampChar[27]<BR>Char(X)Char[X+1]<BR>Varchar(X)Char[X+1]<BR>Graphic(X)Wchar_t[X+1]<BR>Vargraphic(X)Wchar_t[X+1]<BR>因为C没有date或time数据类型,所以DB2的date或time列将被转换为字符。缺省情况下,使用以下转换格式:mm
dd yyyy hh:mm:ss[am |
pm]。你也可以使用字符数据格式将C的字符数据存放到DB2的date列上。对于DECIMAL数据类型,在C语言中也没有对应的数据类型。但可以使用char数据类型实现。<BR>3)、宿主变量和NULL<BR>大多数程序设计语言(如C)都不支持NULL。所以对NULL的处理,一定要在SQL中完成。我们可以使用主机指示符变量来解决这个问题。在嵌入式SQL语句中,宿主变量和指示符变量共同规定一个单独的SQL类型值。指示变量和前面宿主变量之间用一个空格相分隔。如:<BR>EXEC
SQL SELECT price INTO :price :price_nullflag FROM titles <BR>WHERE
au_id =
"mc3026"<BR>其中,price是宿主变量,price_nullflag是指示符变量。指示符变量的值为:<BR>l-1。表示宿主变量应该假设为NULL。(注意:宿主变量的实际值是一个无关值,不予考虑)。<BR>l=0。表示宿主变量不是NULL。<BR>l>0。表示宿主变量不是NULL。而且宿主变量对返回值作了截断,指示变量存放了截断数据的长度。<BR>所以,上面这个例子的含义是:如果不存在mc3026写的书,那么price_nullflag为-1,表示price为NULL;如果存在,则price为实际的价格。<BR>指示变量也是一种宿主变量,也需要在程序中定义,它对应数据库系统中的数据类型为SMALLINT。为了便于识别宿主变量,当嵌入式SQL语句中出现宿主变量时,必须在变量名称前标上冒号(:)。冒号的作用是,告诉预编译器,这是个宿主变量而不是表名或列名。<BR>3.2.2单行查询<BR>单行查询是通过SELECT
INTO语句完成。当这条语句执行时,查询的结果送入INTO所标志的变量中。如果SQLCODE是100,或者SQLSTATE是02000,则说明没有查询到结果或返回结果为NULL,这时,宿主变量不改变,否则,宿主变量中将包含查询的结果。如:<BR>………….<BR>EXEC
SQL SELECT FIRSTNME INTO :firstname <BR>FROM employee<BR>WHERE
LASTNAME = 'JOHNSON';<BR>………….
<P>3.2.3多行查询<BR>对于多行结果,必须使用游标来完成。游标是一个与SELECT语句相关联的符号名,它使用户可逐行访问由DB2返回的结果集。下面这个例子演示了游标的使用方法。这个例子的作用是,逐行打印出每个经理的名字和部门。<BR>#include
<stdio.h><BR>#include <stdlib.h><BR>#include
<string.h><BR>#include "util.h"<BR>EXEC SQL INCLUDE
SQLCA;<BR>#define CHECKERR(CE_STR) if (check_error (CE_STR,
&sqlca) != 0) return 1;<BR>int main(int argc, char *argv[])
{<BR>EXEC SQL BEGIN DECLARE SECTION;<BR>char pname[10];<BR>short
dept;<BR>char userid[9];<BR>char passwd[19];<BR>EXEC SQL END DECLARE
SECTION;<BR>printf( "Sample C program: CURSOR \n" );<BR>if (argc ==
1) {<BR>EXEC SQL CONNECT TO sample;<BR>CHECKERR ("CONNECT TO
SAMPLE");<BR>}<BR>else if (argc == 3) { <BR>strcpy (userid,
argv[1]);<BR>strcpy (passwd, argv[2]);<BR>EXEC SQL CONNECT TO sample
USER :userid USING :passwd;<BR>CHECKERR ("CONNECT TO
SAMPLE");<BR>}<BR>else {<BR>printf ("\nUSAGE: cursor [userid
passwd]\n\n");<BR>return 1;<BR>} /* endif */<BR><BR>EXEC SQL DECLARE
c1 CURSOR FOR (1)<BR>SELECT name, dept FROM staff WHERE
job='Mgr'<BR>FOR UPDATE OF job;<BR>EXEC SQL OPEN c1; (2)<BR>CHECKERR
("OPEN CURSOR");<BR>do {<BR>EXEC SQL FETCH c1 INTO :pname, :dept;
(3)<BR>if (SQLCODE != 0) break;<BR>printf( "%-10.10s in dept. %2d
will be demoted to Clerk\n",<BR>pname, dept );<BR>} while ( 1
);<BR>EXEC SQL CLOSE c1; (4)<BR>CHECKERR ("CLOSE CURSOR");<BR>EXEC
SQL ROLLBACK;<BR>CHECKERR ("ROLLBACK");<BR>printf( "\nOn second
thought -- changes rolled back.\n" );<BR>EXEC SQL CONNECT
RESET;<BR>CHECKERR ("CONNECT RESET");<BR>return 0;<BR>}<BR>/* end of
program : CURSOR.SQC
*/<BR>在上面这个程序中,<BR>(1)定义了一个游标,并指明游标的名字为C1,同时给出了相对于游标的查询语句和游标类型(UPDATE)。<BR>(2)打开游标。系统执行查询语句,建立结果表,将游标指针指向第一条记录之前。<BR>(3)FETCH语句将指针的下一条记录取出,将记录中的数据存放在相应的宿主变量中。同时指针下移。<BR>(4)用CLOSE关闭游标。
<P>3.2.4插入、删除和修改操作<BR>DB2中的插入、删除和修改操作同SQL语句中INSERT、DELETE和UPDATE语句类似。只需在相应的SQL语句前加上EXEC
SQL即可。请看下面这个例子:<BR>例、将staff表中所有工作为“Mgr”的职工的工作改变为“clerk”,并将staff表中所有工作为“sale”的职工信息删除。最后插入一新行。<BR>#include
<stdio.h><BR>#include <string.h><BR>#include
<stdlib.h><BR>#include <sqlenv.h><BR>#include
"util.h"<BR>EXEC SQL INCLUDE SQLCA; (1)<BR>#define CHECKERR(CE_STR)
if (check_error (CE_STR, &sqlca) != 0) return 1;<BR>int main(int
argc, char *argv[]) {<BR>EXEC SQL BEGIN DECLARE SECTION; (2)<BR>char
statement[256];<BR>char userid[9];<BR>char passwd[19];<BR>char
jobUpdate[6];<BR>EXEC SQL END DECLARE SECTION;<BR>printf( "\nSample
C program: UPDAT \n");<BR>if (argc == 1) {<BR>EXEC SQL CONNECT TO
sample;<BR>CHECKERR ("CONNECT TO SAMPLE");<BR>}<BR>else if (argc ==
3) { <BR>strcpy (userid, argv[1]);<BR>strcpy (passwd,
argv[2]);<BR>EXEC SQL CONNECT TO sample USER :userid USING :passwd;
(3)<BR>CHECKERR ("CONNECT TO SAMPLE");<BR>}<BR>else {<BR>printf
("\nUSAGE: updat [userid passwd]\n\n");<BR>return 1;<BR>} /* endif
*/<BR>strcpy (jobUpdate, "Clerk");<BR>EXEC SQL UPDATE staff SET job
= :jobUpdate WHERE job = 'Mgr'; (4)<BR>CHECKERR ("UPDATE
STAFF");<BR>printf ("All 'Mgr' have been demoted to 'Clerk'!\n"
);<BR>strcpy (jobUpdate, "Sales");<BR>EXEC SQL DELETE FROM staff
WHERE job = :jobUpdate; (5)<BR>CHECKERR ("DELETE FROM
STAFF");<BR>printf ("All 'Sales' people have been
deleted!\n");<BR>EXEC SQL INSERT INTO staff <BR>VALUES (999,
'Testing', 99, :jobUpdate, 0, 0, 0); (6)<BR>CHECKERR ("INSERT INTO
STAFF");<BR>printf ("New data has been inserted\n");<BR>EXEC SQL
ROLLBACK; (7)<BR>CHECKERR ("ROLLBACK");<BR>printf( "On second
thought -- changes rolled back.\n" );<BR>EXEC SQL CONNECT
RESET;<BR>CHECKERR ("CONNECT RESET");<BR>return 0;<BR>}<BR>/* end of
program : UPDAT.SQC
*/<BR>上述语句:<BR>(1)包含SQLCA结构。该结构用于将SQL语句执行的结果信息返回给应用程序。<BR>(2)宿主变量定义。<BR>(3)连接到DB2的SAMPLE数据库。<BR>(4)UPDATE语句将staff表中所有工作为“Mgr”的职工的工作改变为“clerk”。<BR>(5)DELETE语句将staff表中所有工作为“sale”的职工信息删除。<BR>(6)INSERT语句插入一新行。
<P>指定位置的UPDATE语句和DELETE语句
<P>游标操作除了可以将多行的查询结果返回给应用程序,它还可以与UPDATE语句和DELETE相结合,根据游标当前的位置,对指针所指的这个行数据执行UPDATE操作和DELETE操作。它的语法为:<BR>UPDATE….
WHERE CURRENT OF cursor_name<BR>DELETE [FROM] {table_name | v<A
href="http://school.21tx.com/office/ie/" target=_blank>IE</A>w_name}
WHERE CURRENT OF
cursor_name<BR>请看下面这个例子。这个例子的作用是:将部门大于40的员工的工作改变为“clerk”,部门小于等于40的员工信息删除。<BR>#include
<stdio.h><BR>#include <stdlib.h><BR>#include
<string.h><BR>#include "util.h"<BR>EXEC SQL INCLUDE
SQLCA;<BR>#define CHECKERR(CE_STR) if (check_error (CE_STR,
&sqlca) != 0) return 1;<BR>int main(int argc, char *argv[])
{<BR>EXEC SQL BEGIN DECLARE SECTION;<BR>char pname[10];<BR>short
dept;<BR>char userid[9];<BR>char passwd[19];<BR>EXEC SQL END DECLARE
SECTION;<BR>printf( "Sample C program: OPENFTCH\n" );<BR>if (argc ==
1) {<BR>EXEC SQL CONNECT TO sample; <BR>CHECKERR ("CONNECT TO
SAMPLE"); <BR>}<BR>else if (argc == 3) { <BR>strcpy (userid,
argv[1]);<BR>strcpy (passwd, argv[2]);<BR>EXEC SQL CONNECT TO sample
USER :userid USING :passwd; <BR>CHECKERR ("CONNECT TO SAMPLE");
<BR>}<BR>else {<BR>printf ("\nUSAGE: openftch [userid
passwd]\n\n");<BR>return 1;<BR>} /* endif */<BR>EXEC SQL DECLARE c1
CURSOR FOR <BR>SELECT name, dept FROM staff WHERE job='Mgr'<BR>FOR
UPDATE OF job;<BR>EXEC SQL OPEN c1; <BR>CHECKERR ("OPEN
CURSOR");<BR><BR>do {<BR>EXEC SQL FETCH c1 INTO :pname, :dept;
<BR>if (SQLCODE != 0) break;<BR><BR>if (dept > 40) {<BR>printf(
"%-10.10s in dept. %2d will be demoted to Clerk\n",<BR>pname, dept
);<BR>EXEC SQL UPDATE staff SET job = 'Clerk' <BR>WHERE CURRENT OF
c1;<BR>CHECKERR ("UPDATE STAFF");<BR>} else {<BR>printf ("%-10.10s
in dept. %2d will be DELETED!\n",<BR>pname, dept);<BR>EXEC SQL
DELETE FROM staff WHERE CURRENT OF c1;<BR>CHECKERR ("DELETE");<BR>}
/* endif */<BR>} while ( 1 );<BR><BR>EXEC SQL CLOSE c1; <BR>CHECKERR
("CLOSE CURSOR");<BR>EXEC SQL ROLLBACK;<BR>CHECKERR
("ROLLBACK");<BR>printf( "\nOn second thought -- changes rolled
back.\n" );<BR>EXEC SQL CONNECT RESET;<BR>CHECKERR ("CONNECT
RESET");<BR>return 0;<BR>}<BR>/* end of program : OPENFTCH.SQC */
<P>在通过游标进行UPDATE和DELETE操作时,相应的游标在定义时必须加上FOR
UPDATE子句。操作时,游标必须打开,而且正指向一行数据。<BR>3.2.5
SQLCA<BR>应用程序执行时,每执行一条SQL语句,就返回一个状态符和一些附加信息。这些信息反映了SQL语句或API的执行情况,它有助于用户分析应用程序的错误所在。这些信息都存放在一个定义在sqlca.h的sqlca结构中。如果一个源文件中后SQL语句,则必须要在源程序中定义一个SQLCA结构,而且名为SQLCA。最简单的定义方法是在源文件中加入一些语句:EXEC
SQL INCLUDE sqlca.h<BR>下面,我们首先看看SQLCA的结构:<BR>SQL_STRUCTURE
sqlca<BR>{<BR>_SQLOLDCHAR sqlcaid[8]; /* Eyecatcher = 'SQLCA '
*/<BR>long sqlcabc; /* SQLCA size in bytes = 136 */<BR>#ifdef
DB2_SQL92E<BR>long sql<A href="http://school.21tx.com/photo/cad/"
target=_blank>CAD</A>e; /* SQL return code */<BR>#else<BR>long
sqlcode; /* SQL return code */<BR>#endif<BR>short sqlerrml; /*
Length for SQLERRMC */<BR>_SQLOLDCHAR sqlerrmc[70]; /* Error message
tokens */<BR>_SQLOLDCHAR sqlerrp[8]; /* Diagnostic information
*/<BR>long sqlerrd[6]; /* Diagnostic information */<BR>_SQLOLDCHAR
sqlwarn[11]; /* Warning flags */<BR>#ifdef DB2_SQL92E<BR>_SQLOLDCHAR
sqlstat[5]; /* State corresponding to SQLCODE
*/<BR>#else<BR>_SQLOLDCHAR sqlstate[5]; /* State corresponding to
SQLCODE
*/<BR>#endif<BR>};<BR>结构中各个字段的作用是:<BR>lSqlcaid:包含字符串“SQLCA”。<BR>lSqlcabc:包含SQLCA结构的长度。<BR>lSqlcode:该值反映了SQL语句执行后的状态,0表示SQL执行成功;<0表示SQL语句执行出错;>0反映了一些特殊情况(如:没有查询结果)。不同的数据库产品,该值代表的含义可能不同。<BR>lSqlerrml:sqlerrmc域中数据的实际长度。<BR>lSqlerrmc:由0个或多个字符串组成,它对返回的值给予一个更详细的解释。<BR>lSqlerrp:包含一些对用户没有用的信息。<BR>lSqlwarn:包含了一些警告信息。<BR>lSqlstate:长度为5的字符串。它表示SQL语句执行的结果。它的每一个含义是遵循ANSI/SQL
92标准。各个数据库产品的sqlstate域的含义都是相同的。<BR>为了更方便地读取sqlca中SQL语句执行后的结果或错误,DB2提供了一个函数——sqlaintp,它在sql.h中声明:sqlaintp(msgbuf,bufsize,linesize,sqlcaptr)。其中msgbuf中存放信息;bufsize中存放了msgbuf的长度;linesize中存放了两个执行符之间的字符长度。函数的返回值为正,代表信息的长度;为负代表没有信息返回。<BR>下面这个例子解释了sqlca和sqlaintp的使用方法:<BR>int
check_error (char eString[], struct sqlca *caPointer) {<BR>char
eBuffer[1024];<BR>char sBuffer[1024];<BR>short rc,
Erc;<BR>/*通过SQLCODE来判断是否出错*/<BR>if (caPointer->sqlcode != 0)
{<BR>printf ("--- error report ---\n");<BR>printf ("ERROR occured :
%s.\nSQLCODE : %ld\n", eString,<BR>caPointer->sqlcode);<BR>/*
获取SQLSTATE信息*/<BR>rc = sqlogstt (sBuffer, 1024, 80,
caPointer->sqlstate);<BR>/*获取调用API的错误信息*/<BR>Erc = sqlaintp
(eBuffer, 1024, 80, caPointer);<BR>/* Erc中存放了eBuffer 的长度*/<BR>if
(Erc > 0) printf ("%s", eBuffer);<BR>if (caPointer->sqlcode
< 0) { /*错误信息*/<BR>if (rc == 0) {<BR>printf ("\n%s",
sBuffer);<BR>}<BR>printf ("--- end error report ---\n");<BR>return
1;<BR>} else {<BR>/* 仅仅是警告信息 */<BR>if (rc == 0) {<BR>printf ("\n%s",
sBuffer);<BR>}<BR>printf ("--- end error report ---\n");<BR>printf
("WARNING - CONTINUING PROGRAM WITH WARNINGS!\n");<BR>return 0;<BR>}
/* endif */<BR>} /* endif */<BR>return
0;<BR>}<BR>在每条SQL语句执行后都返回一个SQLCA结构,SQLCA结构中记载了SQL语句执行后的结果信息。用户可以根据返回信息执行各种操作。DB2也提供了WHENEVER语句。具体可参见SQL
SERVER中的WHENEVER。但是,在DB2中,没有WHENEVER…CALL这个处理。<BR>3.2.6事务<BR>所谓事务,就是一系列应用程序和数据库之间交互操作的集合。一旦一个事务开始执行,则事务中的操作要么全部执行,要么全部不执行。<BR>l事务开始:DB2事务是隐式开始的,除了下列的一些语句,其他任何一个可执行的SQL语句都隐式地开始一个事务。<BR>BEGIN
DECLARE SECTION END DECLARE SECTION<BR>DECLARE CURSOR INCLUDE SQLCA
INCLUDE
SQLDA<BR>WHENEVER<BR>l事务结束:事务由一个可执行的SQL语句开始,后面执行的所有SQL语句都将属于同一个事务,该事务一直遇到COMMIT或ROLLBACK命令时才结束。<BR>COMMIT操作的作用是,结束当前的事务,事务对数据库所做的修改永久化。ROLLBACK的作用是,结束当前的事务,将被修改的数据恢复到事务执行以前的状态,即取消事务执行产生的影响。当程序结束时,系统自动隐式地执行COMMIT操作,如果系统检测到死锁等<A
href="http://school.21tx.com/pc120/"
target=_blank>故障</A>,则隐式地执行ROLLBACK操作。<BR>3.3
DB2的嵌入SQL程序处理过程<BR>嵌入SQL程序处理,由一个源程序创建为一个可执行文件的过程。如下图所示:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -