我的系统环境:
cent os6.5,本机装oralce 11g,数据库的某个用户下中有张表叫TFB_PHONE_CODE,存放手机号和验证码
从一个简单程序开始学习。
程序示例
程序名为test.pc,注意后缀。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlca.h>
EXEC sql INCLUDE sqlCA;
int main()
{
EXEC sql BEGIN DECLARE SECTION;
char phone_str[13];
char userid[9]="in***";
char passwd[19]="in***";
EXEC sql END DECLARE SECTION;
EXEC sql CONNECT:userid IDENTIFIED BY :passwd;
EXEC sql SELECT PHONE INTO :phone_str
FROM TFB_PHONE_CODE
WHERE CODE = '6401';
printf("phone = %s\n",phone_str);
EXEC sql COMMIT WORK RELEASE;
return 0;
}
代码分析
程序很简单。
EXEC sql INCLUDE sqlCA;语句定义并描述了sqlCA的结构。sqlCA用于应用程序和数据库之间的通讯,其中的sqlCODE返回sql语句执行后的结果状态。
在BEGIN DECLARE SECTION
和
END DECLARE SECTION
之间定义了宿主变量。宿主变量可被sql语句引用,也可以被C语言语句引用。它用于将程序中的数据通过sql语句传给数据库管理器,或从数据库管理器接收查询的结果。在sql语句中,主变量前均有“:”标志以示区别。
访问数据库之前必须做CONNECT操作,以连接到某一个数据库上。用户名和密码的方式连接。注意宿主变量冒号的使用。
EXEC sql SELECT PHONE INTO :firstname FROM TFB_PHONE_CODE WHERE CODE = '6401';
是一条选择语句。它将表TFB_PHONE_CODE中的code为“6401”的行数据的PHONE查出,并将它放在phone_str变量中。该语句返回一个结果。可以通过游标返回多个结果
EXEC sql COMMIT WORK RELEASE;
是提交并释放数据库连接,当然select语句也可以不用提交。
编译运行
[**@localhost proc]$ proc test.pc
[**@localhost proc]$ ls
test.c test.lis test.pc
proc命令生成.c和.lis两个文件,我们要用到*.c文件来继续生成执行文件。
[**@localhost proc]$ gcc test.c
test.c:146:19: 错误:sqlca.h:没有那个文件或目录
这一步报错,说找不到sqlca.h文件,但是我用find查找了下,在$ORACLE_HOME/public/目录下找到了这个文件,但是gcc不能默认找到,那就手动加上路径再次编译。
[**@localhost proc]$ gcc -o test test.c -I $ORACLE_HOME/precomp/public
/tmp/ccfPShLN.o: In function `main':
test.c:(.text+0x23e): undefined reference to `sqlcxt'
test.c:(.text+0x3d9): undefined reference to `sqlcxt'
test.c:(.text+0x479): undefined reference to `sqlcxt'
前面的错误解决了,又有新的错误,谷歌了下,找到解决方案,继续编译。
[**@localhost proc]$ gcc -o test test.c -I $ORACLE_HOME/precomp/public -L $ORACLE_HOME/lib -l clntsh
[**@localhost proc]$ ls
test test.c test.lis test.pc
成功了!
[**@localhost proc]$ ./test
./test: error while loading shared libraries: libclntsh.so.11.1: cannot open shared object file: No such file or directory
额,出错,找不到动态库。继续谷歌,说是要配置
LD_LIBRARY_PATH包含$ORALCE_HOME/lib,但是我看了下自己的.bash_profile,已经配置了,又执行了下
source命令,再次运行,成功。
[**@localhost proc]$ ./test
phone = 138*********
游标的使用
什么是游标
我理解游标的作用是快速定位,像个标尺一样把检索的数据结果保存在内存中,并做好标记,读取时就很快。
使用示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlca.h>
EXEC sql INCLUDE sqlCA;
int main()
{
EXEC sql BEGIN DECLARE SECTION;
char phone_str[13];
char userid[9]="in***";
char passwd[19]="in***";
char sql_str[256] = "select phone from TFB_PHONE_CODE where code ='6401'";
EXEC sql END DECLARE SECTION;
EXEC sql CONNECT:userid IDENTIFIED BY :passwd;
EXEC sql PREPARE sql_find_phone from :sql_str;
EXEC sql DECLARE CurPhone CURSOR FOR sql_find_phone;
EXEC sql OPEN CurPhone;
for(;;)
{
if(sqlca.sqlcode == 1403)
break;
EXEC sql FETCH CurPhone INTO:phone_str;
printf("phone = %s\n",phone_str);
printf("sqlca.sqlcode = %d\n",sqlca.sqlcode);
}
printf("sqlca.sqlerrd[2] = %d\n",sqlca.sqlerrd[2]);
EXEC sql CLOSE CurPhone;
EXEC sql COMMIT WORK RELEASE;
return 0;
}
EXEC sql DECLARE CurPhone CURSOR FOR sql_find_phone
这句是对一个检索语句申请游标
EXEC sql OPEN CurPhone;
打开游标。
EXEC sql FETCH CurPhone INTO:phone_str;
循环体中,把检索的结果放进phone_str这个变量。
sqlca.sqlerrd[2]
当sql语句成功时,保存当前sql语句处理的行数,它要在fetch后才会生效。这个示例中符合条件的记录是两条,所以sqlca.sqlerrd[2]的值是2。
输出结果:
phone = 138*******
sqlca.sqlcode = 0
phone = 159******
sqlca.sqlcode = 0
phone = 159******
sqlca.sqlcode = 1403
sqlca.sqlerrd[2] = 2
注意第三笔记录读取的号码其实还是第二笔的,因为已经没有记录了,没取到还是缓存的上次的值。
其实还可以换一种写法,这样输出就比较清晰了:
int main()
{
EXEC sql BEGIN DECLARE SECTION;
char phone_str[13];
char userid[9]="in***";
char passwd[19]="in***";
char sql_str[256] = "select phone from TFB_PHONE_CODE where code ='6401'";
EXEC sql END DECLARE SECTION;
EXEC sql CONNECT:userid IDENTIFIED BY :passwd;
EXEC sql PREPARE sql_find_phone from :sql_str;
EXEC sql DECLARE CurPhone CURSOR FOR sql_find_phone;
EXEC sql OPEN CurPhone;
EXEC sql WHENEVER NOT FOUND DO BREAK;
for(;;)
{
EXEC sql FETCH CurPhone INTO:phone_str;
printf("phone = %s\n",sqlca.sqlerrd[2]);
EXEC sql CLOSE CurPhone;
EXEC sql COMMIT WORK RELEASE;
return 0;
}
phone = 138*****
sqlca.sqlcode = 0
phone = 159****
sqlca.sqlcode = 0
sqlca.sqlerrd[2] = 2
EXEC sql WHENEVER NOT FOUND DO BREAK; 相当于给循环设置了一个条件,如果没有记录了,就退出。