2.应用程序体
在Pro*C程序中, 能把SQL语句和C语句自由地混合书写,并能在SQL语句中使用SQL变量,嵌入式SQL语句的书写文法是:
l 以关键字EXEC SQL开始
l 以C语言的语句终结符(分号)终结
SQL语句的作用主要用于同数据库打交道。C语言程序用于控制,输入,输出和数据处理等。
(1) 连接到ORACLE数据库
在对数据库存取之前,必须先把程序与ORACLE数据库连接起来。即登录到ORACLE上。所连接命令应该是应用程序的第一个可执行命令。连接命令格式如下:
EXEC SQL CONNECT:< 用户名 > IDENTIFIED BY : < 口令 >
或EXEC SQL CONNECT: < 用户名 > / < 口令 >
在使用上述两种格式进行登入时, 应当首先在说明段定义包含用户名和口令的
SQL 变量,并在执行CONNECT之前设置它们,否则会造成登录失败。例如:
EXEC SQL BEGIN DECLARE SECTION ;
VARCHAR usename [20];
VARCHAR password[20];
EXEC SQL END DECLARE
..........
strcpy ( usename.arr, “CSOTT’);
usename.len = strlen (username.arr);
strcpy (password.arr , “TIGER’);
password .len = strlen( password .arr);
EXEC SQL WHENEVER SQLERROR GOTO SQLERR;
EXEC SQL CONNECT :username INDNTIFIED BY : password;
注意: 不能把用户名和口令直接编写到CONNECT语句中,或者把用引号(’)括起来的字母串在CONNECT 语句中, 如下面的语句是无效的。
EXEC SQL CONNECT SCOTT INENTIFIED BY TIGER;
EXEC SQL CONNECT ‘SCOTT’ IDENTIFIED BY ‘TIGER’;
(2). 插入、更新和删除
在讲述SQL语言时已详细讲过, 这里就不举例说明了。
(3). 数据库查询及游标的使用
在PRO*C中, 查询可分为两种类型:
l 返回单行或定行数的查询;
l 返回多行的查询.此种查询要求使用游标来控制每一行或每一组(主变量用数组).
1) 返回单行或定行数的查询
在PRO*C中的查询SQL SELECT语句由以下几个子句组成:
SELECT
INTO
FROM
WHERE
CONNECT BY
UNION
INTERSECT
MINUS
GROUP BY
HAVING
ORDER BY
其中WHERE子句中的查询条件可以是一个属性或多个属性的集合,在执行是赋值的主变量也可放在WHERE子句中.WHERE子句中所用的主变量称为输入主变量。如:
SELECT EMPNO, JOB, SAL
INTO:PNAME, :PJOB, :PSAL
FROM EMP
WHERE EMPNO=:PEMPNO;
若没有找到限定的行, 则SQLCA.SQLCODE返回” 1403”, 表明”没有找到”。
INTO从句中的主变量叫输出主变量,它提供了查询时所需要的信息。
在任何项送给主变量之前,都要求ORACLE把这些项转换成主变量的数据类型。对于数字是通过截断来完成的(如:9.23转换为9)。
如果已确定查询只返回一行,那么就不必使用游标,只给SELECT语句增加一个INTO子句即可。在语义上INTO语句在FROM之前的查询中有多少个选择项就有多少个输出主变量。若在SELECT项中表达式的数目不等于INTO子句中主变量的数目,就把SQLCA.SQLWARN[3]置为”W”。
2)多行查询及游标的使用
如果查询返回多行或不知道返回多少行,使用带有ORACLE游标(CURSOR)的SELECT语句。
游标是ORACLE和PRO*C存放查询结果的工作区域。一个游标(已命名的)与一条SELECT语句相关联。操作游标有由4条命令:
(1)DECLARE CURSOR;
(2)OPEN CURSOR;
(3)FETCH;
(4)CLOSE CURSOR。
A. 定义游标
一个游标必须首先定义, 才能使用它。语法为:
EXEC SQL DECLARE 〈游标名〉CORSOR FOR
SELECT 〈列〉
FROM 〈表〉
例如:
EXEC SQL DECLARE CSOR, CURSOR FOR
SELECT ENAME , JOB, SAL
FROM EMP
WHERE DEPTNO=:DEPTNO;
当赋给一个与查询相关联的游标CURSOR之后, 当SELECT查询EMP时可从数据库中返回多行,这些行就是CURSOR的一个活动区域。
注意:
1) 定义游标必须在对游标操作之前完成;
2) PRO*C不能引用没有定义的游标;
3) 游标定义后,其作用范围是整个程序。所以对一个程序来讲, 同时定义两个相同的游标是错误的。
B. 打开游标
打开游标的OPEN语句主要用来输入主变量的内容,这些主要是WHERE中使用的主变量。打开游标的语句是:EXEC SQL OPEN 〈游标名〉
当打开游标后,可以从相关的查询中取出多于一行的结果。所有满足查询标准的行组成一集合,叫做“游标活动集”。通过取操作,活动集中的每一行或每一组是一个一个返回的,查询完成后, 游标就可关闭了。
注意:1)游标处于活动集的第一行前面;
2)若改变了输入主变量就必须重新打开游标。
C. 取数据
从活动集中取出一行或一组把结果送到输出主变量中的过程叫取数据。输出主变量的定义在取数据语句中。取数据的语句如下:
EXEC SQL FETCH〈游标名〉INTO:主变量1,主变量2,……
使用FETCH应注意以下几点:
l 游标必须先定义再打开。
l 只有在游标打开之后才能取数据,即执行FETCH语句。
l FETCH语句每执行一次,从当前行或当前组取数据一次,下一行或下一组向上移一次。游标每次所指的行或组都为当前行或当前组,而FETCH每次都是取游标所指定的行或组的数据。
l 当游标活动集空之后,ORCLE返回一个SQLCA。SQLCA(=1403)。
l 若希望此游标再操作, 必须先关闭再打开它。
l 在C程序中可以开辟一个内存空间,来存放操作结果,这样就能利用开辟的空间来灵活操纵查询的结果。
D.关闭游标
取完活动集中所有行后,必须关闭游标,以释放与该游标有关的资源。
关闭游标的格式为:
EXEC SQL CLOSE 游标名;
例如:
EXEC SQL CLOSE C1;
ORACLE V5.0版支持SQL格式“CURRENT OF CURSOR”。这条语句将指向一个游标中最新取出的行, 以用于修改和删除操作。该语句必须有取操作之后使用,它等同存储一个ROWID,并使用它。
(4).举例
EXEC SQL DECLARE SALESPEOPLE CURSOR FOR
SELECT SSNO, NAME, SALARY
FROM EMPLOYEE
WHERE DNAME=‘Sales’;
EXEC SQL OPEN SALESPEOPLE;
EXEC SQL FETCH SALESPEOPLE
INTO :SS,:NAME,:SAL;
EXEC SQL CLOSE SALESPEOPLE;
(5)SQL嵌套的方法及应用
嵌入SQL与交互式SQL在形式上有如下差别:
1) 在SQL语句前增加前缀“EXEC SQL”, 这一小小的差别其目的是在于预编译时容易识别出来, 以便把每一条SQL作为一条高级语言来处理。
2) 每一SQL语句分为说明性语句和可执行语句两大类。可执行语句又分为数据定义、数据控制、数据操纵、数据检索四大类。
可执行性SQL语句写在高级语言的可执行处;说明性SQL语句写在高级语言的说明性的地方。
例如:在PRO*C程序中建立一个名为BOOK的表结构,过程如下:
#include〈stdio.h〉
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR uid[20], pwd[20];
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;
Main()
{
/*login database*/
strcpy(uid.arr,’wu’);
uid.len=strlen(uid,arr);
strcpy(pwd.arr,’wu’);
pwd.len=strlen(pwd.arr);
EXEC SQL CONNECT:uid IDENTIFEED BY:pwd;
EXEC SQL CREATE TABLE book
( acqnum number, copies number , price number);
EXEC SQL COMMIT WORK RELEASE;
EXIT;
PRO*C可非常简便灵活地访问ORCLE数据库中的数据,同时又具有C语言高速的特点,因而可完成一些ORACLE产品不能完成的任务,例如以下一个固定的特殊格式输出结果。
SQL嵌套源程序示例
#unclude
typedef char asciz[20];
EXEC SQL BEGIN DECLARE SECTION;
EXEC SQL TYPE asciz IS STRING (20) REFERENCE;
asciz username;
asciz password;
asciz emp_name(5);
int emp_number(5a);
float salary[5];
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE sqlca;
Void print_rows();
Void sqlerror();
Main()
{
int num_ret;
strcpy(username,”SCOTT’);
strcpy(password, “TYGER”);
EXEC SQL WHENEVER SQLERROR DO sqlerror();
EXEC SQL CONNECT:username IDENTIFIED BY:password;
Print (“\nConnected to ORACLE as user:%s\n”, username);
EXEC SQL DECLARE c1 CURSOR FOR
SELECT EMPNO , ENAME , SAL FROM EMP;
EXEC SQL OPEN c1;
Num_ret = 0;
For(;;)
{
EXEC SQL WHENEVER NOT FOUND DO break;
EXEC SQL FETCH c1 INTO : emp_number , :emp_name , :salary;
Print_rows (sqlca.sqlerrd[2] – num_ret);
Num_ret=sqlca.sqlerrd[2];
}
if ((sqlca.sqlerrd[2] – num_ret)>0);
print _rows(sqlca.sqlerrd[2] –num_ret);
EXEC SQL CLOSE c1;
Printf(“\Have a good day.\n”);
EXEC SQL COMMIT WORK RELEASE;
}
void print_rows(n);
int n;
{
int i;
printf(“\nNumber Employee Salary\n”);
printf(“------------------------------\n”);
for (i=0;i printf(“% - 9d%- 8s%9.2f\n”,emp-number[i], emp---name[i],salary[i];
}
void sqlerror()
{
EXEC SQL WHENEVER SQLERROR CONTINUE;
Printf(“\noracle error detected:\n”);
Printf(‘\n%.70s\n”, sqlca.sqlerrm.sqlerrmc);
EXEC SQL ROLLBACK WORK RELEASE;
Exit(1);
}
(6) 错误检测和恢复
在使用SQL语句和PRO*C对数据库进行操作时,常常有字段空值,无条件删除,无行返回,数据溢出和截断等现象发生,这种现象可以用SQLCA和指示器变量来检测。
1 SQLCA的结构
在PRO*C程序中SQLCA结构如下:
STRUCT SQLCA{
Char sqlcaid[8];
Long sqlabc;
Long sqlcode;
STRUCT{
Unsigned sqlerrm1;
Char sqlerrmc[10];
}sqlerrm;
Char sqlerrp[8];
Long sqlerrd[6];
Char sqlwarn[8];
Char sqlext[8];
}
其中:
1) SQLCA.sqlerrm.sqlerrmc:带有SQLCA。SQLCODE的错误正文。
2) SQLCA.sqlerrd:当前ORACLE的状态,只有SQLCA.SQLERRD[2]有意义,表示DML语句处理的行数。
3) SQLCA.sqlwarn:提供可能遇到的条件信息。
在每执行一个SQL语句后,ORACLE就把返回结果放入SQLCA中,但说明语句除外。
使用指示变量要注意:
l 在WHERE子句中不能用指示变量。用NULL属性来测试空值。
例如下列子句:
SELECT…
FROM…
WHERE ENAME IS NULL;
是正确的,而
WHERE ENAME=:PEME:PEME1
是错误的。
l 指示变量在插入空值之前为—1
l 可输出空值。
3 WHENEVER语句
WHENEVER是说明语句,不返回SQLCODE, 只是根据SQLCA中的返回码指定相关的措施。格式为
EXEC SQL WHENEVER [SQLERROR|SQLWARNING|NOTFORUND]
[STOP|CONTINUE|GOTO<标号>];
其中
(1)[STOP|CONTINUE|GOT<标号>]的缺省值为CONTINUE。
(2)SQLERROR:SQLCA.SQLCODE<0;
(3)SQLWARNIGN:SQLCA.SQLWARN[0]=“W”;
(4)NOTFOUND:SQLCA.SQLCODE=1403;
下面给出一段程序来说明WHENEVER的用法:
EXEC SQL BEGIN DEELARE SECTION;
VARCHAR UID[20];
VARCHAR PASW[20];
……
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;
Main()
{
……
EXEC SQL WHENEVER SQLERROR GOTO ERR;
EXEC SQL CONNECT:UID/:PWD;
……
EXEC SQL DECLARE CSOR1 CURSOR FOR
SELECT 〈字段〉
FORM〈表〉
EXEC SQL OPEN CSOR1;
SQL
……
EXEC SQL WHENEVER NOT FOUND GOTO good;
For(;;)
EXEC SQL FETCH CSOR, INTO……
Good:
……
printf(“\n查询结束\n”);
EXEC SQL CLOSE C1;
EXEC SQL WHENEVER SQLERROR CONTINUE.
EXEC SQL COMMIT WORK RELEASE:
Exit();
Printf(“\nps|n”, sqlca.sqlerrm.sqlerrmc);
EXEC SQL ROLLBACK WORK RELEASE:
Exit(1);
}