proc*C/C++是一种将SQL操作语句嵌入到c/c++代码中来操作数据库的程序开发方式。这一过程需要用到proc预编译工具。将嵌入了SQL语句的源文件转变成c/c++编译器可以解析的c/c++源文件。
很明显,这种开发方式增加了预编译这一步,增加了麻烦,于是衍生出另一个问题,这么麻烦的东西
为什么还要介绍呢?oracle相关文档给出了如下原因:
1 更方便,更简单让你的应用直接访问oarcle数据库。
2 创建高度定制化的应用。
3 可以密切监测资源利用,SQL语句的执行,以及各种运行指标。
3 调用pl/sql
4 与
其它工具相比,性能更优。这个需要对比才知道。
5 语法、语义检查。
oracle官方文档给出的优点很多,不过,除了上面第5条,其它的我都还没有深刻“领悟”到。倒是发现用proc*c/c++编码的一个缺点:难于调试,预编译时报出的错误描述难以看懂,更别说据此查找问题了。说了这么多,到底为什么学习proc*c/c++编程方式呢?对于我来说,主要是多一种研究oracle的方式。
proc*C/C++编程方式的一般流程是:
pc文件(带嵌入的SQL语句/过程) -------proc预编译----->
*.c/*.cpp文件 -------c/c++编译器-----> 执行文件或者库
首先,不管三七二十一,来一个简单的示例:
1
简单示例
-
#include <stdio.h>
-
#include \"sqlda.h\"
-
#include \"sqlcpr.h\"
-
-
-
#define SQLDESC sqlca.sqlerrm.sqlerrmc
-
#define SQLDESC_LENGTH sqlca.sqlerrm.sqlerrml
-
-
/* output error message */
-
void sql_error(struct sqlca& sqlca)
-
{
-
SQLDESC[SQLDESC_LENGTH] = 0;
-
printf(\"%s\", SQLDESC);
-
}
-
-
/* login database */
-
int proc_login(const char* up, const char* lsn)
-
{
-
EXEC SQL BEGIN DECLARE SECTION;
-
char l_lsn[50];
-
char l_up[50];
-
EXEC SQL END DECLARE SECTION;
-
-
int ret(-1);
-
strcpy(l_up, up);
-
strcpy(l_lsn, lsn);
-
-
EXEC SQL WHENEVER SQLERROR do sql_error(sqlca);
-
EXEC SQL CONNECT :l_up using :l_lsn;
-
-
if (0 == sqlca.sqlcode)
-
ret = 0;
-
-
EXEC SQL WHENEVER SQLERROR continue;
-
return ret;
-
}
-
-
/*
-
insert some records
-
*/
-
int proc_insert(int num)
-
{
-
EXEC SQL BEGIN DECLARE SECTION;
-
int f1;
-
char f2[15];
-
char f3[14]
-
-
EXEC SQL END DECLARE SECTION;
-
-
int ret(-1);
-
EXEC SQL WHENEVER SQLERROR DO sql_error(sqlca);
-
for (int i=1; i<=num; i++)
-
{
-
f1 = i;
-
sprintf(f2,\"Name%d\",i);
-
strcpy(f3,\"bj\");
-
-
-
EXEC SQL INSERT INTO DEPT( DEPTNO, DNAME, LOC) VALUES(:f1, :f2, :f3);
-
}
-
-
EXEC SQL WHENEVER SQLERROR continue;
-
-
EXEC SQL COMMIT; //commit records
-
-
return ret;
-
}
-
-
-
-
/*
-
delete all record
-
*/
-
int proc_delete()
-
{
-
int ret(0);
-
-
EXEC SQL WHENEVER SQLERROR DO sql_error(sqlca);
-
EXEC SQL delete DEPT;
-
EXEC SQL WHENEVER SQLERROR continue;
-
-
-
EXEC SQL COMMIT;
-
-
return ret;
-
}
-
-
-
int main()
-
{
-
//login
-
if (0 != proc_login("scott/tiger", "test"))
-
{
-
//error
-
return 1;
-
}
-
else
-
{
-
proc_insert(100);
-
proc_delete(); return 0;
-
}
-
}
上面这段代码做了三件事:
1连接数据库:
proc_login
2插入100条记录到scott schema下的表DEPT:
proc_insert
3删除DEPT所有记录:
proc_delete
解释一下其中的一些嵌入式SQL语句:
|
嵌入SQL语句
|
说明
|
|
EXEC
SQL BEGIN DECLARE SECTION;
EXEC SQL END DECLARE SECTION;
|
这两句成对使用。用来声明宿主变量的声明段,通常它们中间的宿主变量才会被proc解析和识别。
|
|
EXEC
SQL WHENEVER SQLERROR do sql_error(sqlca);
EXEC SQL WHENEVER SQLERROR continue;
|
第一句的意思是:如果发生错误了就调用sql_error函数。其中sqlca这个变量由proc自动生成,
包含一个大的结构体,其状态由sqlib接口自动设定,我们一般通过它来查询执行状态,所以不要定义跟它一模一样的变量名。
第二句的意思是:如果发生错误了,只管继续(不用做什么操作)。这句话实际是对上面这一句话的重置。
通过阅读预编译后的c/c++文件,你会有深刻认识!
|
|
EXEC
SQL CONNECT :l_up using :l_lsn;
|
这句话是连接数据库的一种方法。还有其它方式,后面可能会介绍哦:)
|
|
EXEC
SQL INSERT
INTO DEPT( DEPTNO, DNAME, LOC) VALUES(:f1, :f2, :f3);
|
插入一条记录到DEPT表中。(如此简单的一句话,预编译以后变得老长了!)
|
|
EXEC SQL COMMIT;
|
提交记录。
|
|
EXEC SQL delete DEPT;
|
删除DEPT表中所有的记录。
|
2 预编译
上面一段代码,立刻用gcc或者visual studio 编译,是通不过的。先要经过proc预编译工具转换其中的SQL语句,再才能用c/c++编译器编译。
oracle公司没有单独发布proc工具,通常需要先安装oracle服务端/客户端程序。在$ORACLE_HOME/BIN/里能找到proc工具。
假设将上面的代码保存到d:\proc_test\exam_conn.pc文件中,在windows的命令行或者linux下的terminal中均可用proc预编译它:
-
proc parse=none def_sqlcode=yes iname=D:\proc_test\exam_conn.pc oname=D:\proc_test\exam_conn.c
在iname指定的位置,我们将得到一个exam_conn.c文件。
首先解释一下上面用到的几个编译选项:
|
option
|
说明
|
parse=none
|
表示只解析定义在声明段中的宿主变量。
|
def_sqlcode=yes
|
产生 '#define SQLCODE sqlca.sqlcode' 宏
|
iname=...
|
表示输入文件
|
oname=...
|
表示输出文件
|
也可以将上面的命令行写进一个文件exam_conn.cfg里。关于在vs2008中结合proc工具预编译pc文件,可以参考我的一篇博文:
http://niyirangrujiu.blog.163.com/blog/static/981733720155431833709/
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/26320972/viewspace-1688434/
,如需转载,请注明出处,否则将追究法律责任。