return buffer; }
/******************************************************************************* PROCEDURE : readCol * 返回列数据。
******************************************************************************/ char * readCol (SQLDA *sqldaPointer, short sd_columnIndex, char * buffer){ short numBytes;
short idx, ind ; /* Array idx variables */
/* Variables for decoding packed decimal data */ char tmpstr[1024]; short collen; char *dataptr; /* 检查是否为NULL */
if ( sqldaPointer->sd_column[sd_columnIndex].sd_sqlind ) { buffer[0] = 0; return buffer; }
/*返回列数据到buffer变量*/
strcpy( buffer, (char *) sqldaPointer->sd_column[ sd_columnIndex ].sd_sqldata); return buffer; }
/* COMMENT OUT OFF */ 第三节 IBM DB2嵌入SQL语言
DB2支持SQL嵌入到C/C++、JAVA、COBOL、FORTRAN和REXX等语言。本节以SQL嵌入C/C++为例子,讲解静态的嵌入SQL编程和动态的嵌入SQL编程。
静态SQL嵌入C语言编程是指,应用程序在书写时,每个SQL语句的大部分都已确定下来(如:查询的表、列和语句的格式等),唯一不确定的是查询语句中某些特定变量的值,这些值可以在执行时由变量传进去,但是,值的类型要事先确定。 3.1 一个简单示例
首先,我们来看一个嵌入静态SQL语句的C程序。
例1、连接到SAMPLE数据库,查询LASTNAME为JOHNSON的FIRSTNAME信息。 #include
EXEC SQL INCLUDE SQLCA; (1)
#define CHECKERR(CE_STR) if (check_error (CE_STR, &sqlca) != 0) return 1; int check_error (char eString[], struct sqlca *caPointer) { char eBuffer[1024]; char sBuffer[1024]; short rc, Erc;
if (caPointer->sqlcode != 0) { printf (--- error report ---\\n);
printf (ERROR occured : %s.\\nSQLCODE : %ld\\n, eString, caPointer->sqlcode); } return 0; }
int main(int argc, char *argv[]) {
EXEC SQL BEGIN DECLARE SECTION; (2) char firstname[13]; char userid[9]; char passwd[19];
EXEC SQL END DECLARE SECTION; printf( Sample C program: STATIC\\n ); if (argc == 1) {
EXEC SQL CONNECT TO sample; CHECKERR (CONNECT TO SAMPLE); }
else if (argc == 3) { strcpy (userid, argv[1]); strcpy (passwd, argv[2]);
EXEC SQL CONNECT TO sample USER :userid USING :passwd; (3) CHECKERR (CONNECT TO SAMPLE); } else {
printf (\\nUSAGE: static [userid passwd]\\n\\n); return 1; } /* endif */
EXEC SQL SELECT FIRSTNME INTO :firstname FROM employee
WHERE LASTNAME = JOHNSON;(4) CHECKERR (SELECT statement); (5) printf( First name = %s\\n, firstname ); EXEC SQL CONNECT RESET; (6) CHECKERR (CONNECT RESET); return 0; }
/* end of program : STATIC.SQC */
上面是一个简单的静态嵌入SQL语句的应用程序。它包括了静态嵌入SQL的主要部分。
(1)中的include SQLCA语句定义并描述了SQLCA的结构。SQLCA用于应用程序和数据库之间的通讯,其中的SQLCODE返回SQL语句执行后的结果状态。
(2)在BEGIN DECLARE SECTION和END DECLARE SECTION之间定义了主变量。主变量可被SQL语句引用,也可以被C语言语句引用。它用于将程序中的数据通过SQL语句传给数据库管理器,或从数据库管理器接收查询的结果。在SQL语句中,主变量前均有―:‖标志以示区别。
(3)在每次访问数据库之前必须做CONNECT操作,以连接到某一个数据库上。这时,应该保证数据库实例已经启动。
(4)是一条选择语句。它将表employee中的LASTNAME为―JOHNSON‖的行数据的FIRSTNAME查出,并将它放在firstname变量中。该语句返回一个结果。可以通过游标返回多个结果。
(5)在该程序中通过调用宏CHECKERR(即调用函数check_error)来返回SQL语句执行的结果。Check_error函数在下面讲解。 (6)最后断开数据库的连接。
从上例看出,每条嵌入式SQL语句都用EXEC SQL开始,表明它是一条SQL语句。这也是告诉预编译器在EXEC SQL和―;‖之间是嵌入SQL语句。如果一条嵌入式SQL语句占用多行,在C程序中可以用续行符―\\‖。
3.2 嵌入SQL语句 3.2.1宿主变量 1)、声明方法
宿主变量就是在嵌入式SQL语句中引用主语言说明的程序变量(如上例中的firstname变量)。如: ………….
EXEC SQL SELECT FIRSTNME INTO :firstname (4) FROM employee
WHERE LASTNAME = JOHNSON; ………….
在嵌入式SQL语句中使用宿主变量前,必须采用BEGIN DECLARE SECTION 和END DECLARE SECTION之间给宿主变量说明。这两条语句不是可执行语句,而是预编译程序的说明。宿主变量是标准的C程序变量。嵌入SQL语句使用宿主变量把数据库中查询到的值返回给应用程序(称为输出宿主变量),也用于将程序中给定的值传到SQL语句中(称为输入宿主变量)。显然,C程序和嵌入SQL语句都可以访问宿主变量。
在使用宿主变量前,请注意以下几点:
l宿主变量的长度不能超过30字节。开始的字母不能是EXEC和SQL。 l宿主变量必须在被引用之前定义。
l一个源程序文件中可以有多个SQL说明段。 l宿主变量名在整个程序中必须是唯一的。 2)、宿主变量的数据类型
宿主变量是一个用程序设计语言的数据类型说明并用程序设计语言处理的程序变量;另外,在嵌入SQL语句中用宿主变量保存数据库数据。所以,在嵌入SQL语句中,必须映射C数据类型为合适的DB2数据类型。必须慎重选择宿主变量的数据类型。请看下面这个例子: EXEC SQL BEGIN DECLARE SECTION; short hostvar1 = 39; char *hostvar2 = telescope;
EXEC SQL END DECLARE SECTION; EXEC SQL UPDATE inventory SET department = :hostvar1 WHERE part_num = 4572-3; EXEC SQL UPDATE inventory SET prod_descrip = :hostvar2 WHERE part_num = 4572-3;
在第一个update语句中,department列为smallint数据类型,所以应该把hostvar1定义为short数据类型。这样的话,从C到DB2的hostvar1可以直接映射。在第二个update语句中,prod_descip列为varchar数据类型,所以应该把hostvar2定义为字符数组。这样的话,从C到DB2的hostvar2可以从字符数组映射为varchar数据类型。
下表列出了C的数据类型和DB2的数据类型的一些转换关系: DB2数据类型C数据类型 Smallintshort IntegerLong Decimal(p,s)无 DoubleDouble DateChar[11] TimeChar[9] TimestampChar[27] Char(X)Char[X+1] Varchar(X)Char[X+1] Graphic(X)Wchar_t[X+1] Vargraphic(X)Wchar_t[X+1]
因为C没有date或time数据类型,所以DB2的date或time列将被转换为字符。缺省情况下,使用以下转换格式:mm dd yyyy hh:mm:ss[am | pm]。你也可以使用字符数据格式将C的字符数据存放到DB2的date列上。对于DECIMAL数据类型,在C语言中也没有对应的数据类型。但可以使用char数据类型实现。
3)、宿主变量和NULL
大多数程序设计语言(如C)都不支持NULL。所以对NULL的处理,一定要在SQL中完成。我们可以使用主机指示符变量来解决这个问题。在嵌入式SQL语句中,宿主变量和指示符变量共同规定一个单独的SQL类型值。指示变量和前面宿主变量之间用一个空格相分隔。如: EXEC SQL SELECT price INTO :price :price_nullflag FROM titles WHERE au_id = mc3026
其中,price是宿主变量,price_nullflag是指示符变量。指示符变量的值为:
l-1。表示宿主变量应该假设为NULL。(注意:宿主变量的实际值是一个无关值,不予考虑)。 l=0。表示宿主变量不是NULL。
l>0。表示宿主变量不是NULL。而且宿主变量对返回值作了截断,指示变量存放了截断数据的长度。 所以,上面这个例子的含义是:如果不存在mc3026写的书,那么price_nullflag为-1,表示price为NULL;如果存在,则price为实际的价格。
指示变量也是一种宿主变量,也需要在程序中定义,它对应数据库系统中的数据类型为SMALLINT。为了便于识别宿主变量,当嵌入式SQL语句中出现宿主变量时,必须在变量名称前标上冒号(:)。冒号的作用是,告诉预编译器,这是个宿主变量而不是表名或列名。 3.2.2单行查询
单行查询是通过SELECT INTO语句完成。当这条语句执行时,查询的结果送入INTO所标志的变量中。如果SQLCODE是100,或者SQLSTATE是02000,则说明没有查询到结果或返回结果为NULL,这时,宿主变量不改变,否则,宿主变量中将包含查询的结果。如: ………….
EXEC SQL SELECT FIRSTNME INTO :firstname FROM employee
WHERE LASTNAME = JOHNSON; …………. 3.2.3多行查询
对于多行结果,必须使用游标来完成。游标是一个与SELECT语句相关联的符号名,它使用户可逐行访问由DB2返回的结果集。下面这个例子演示了游标的使用方法。这个例子的作用是,逐行打印出每个经理的名字和部门。 #include
EXEC SQL INCLUDE SQLCA;
#define CHECKERR(CE_STR) if (check_error (CE_STR, &sqlca) != 0) return 1; int main(int argc, char *argv[]) {
EXEC SQL BEGIN DECLARE SECTION; char pname[10]; short dept; char userid[9]; char passwd[19];
EXEC SQL END DECLARE SECTION; printf( Sample C program: CURSOR \\n ); if (argc == 1) {
EXEC SQL CONNECT TO sample; CHECKERR (CONNECT TO SAMPLE); }
else if (argc == 3) { strcpy (userid, argv[1]); strcpy (passwd, argv[2]);
EXEC SQL CONNECT TO sample USER :userid USING :passwd; CHECKERR (CONNECT TO SAMPLE); } else {
printf (\\nUSAGE: cursor [userid passwd]\\n\\n); return 1; } /* endif */
EXEC SQL DECLARE c1 CURSOR FOR (1) SELECT name, dept FROM staff WHERE job=Mgr FOR UPDATE OF job; EXEC SQL OPEN c1; (2) CHECKERR (OPEN CURSOR); do {
EXEC SQL FETCH c1 INTO :pname, :dept; (3) if (SQLCODE != 0) break;
printf( %-10.10s in dept. - will be demoted to Clerk\\n,