PRO*C程序移植为DBLIBRARY/C程序经验谈
2006-07-26 23:15:35 来源:WEB开发网核心提示:PRO*C程序移植为DBLIBRARY/C程序经验谈刘小余农行信用卡有关程序以前均为PRO*C程序,与Oracle(大型网站数据库平台)数据库相连,PRO*C程序移植为DBLIBRARY/C程序经验谈,总行为与其它业务系统一致,将信用卡系统移植为SYBASE数据库下,作者也仅是略窥门径,希望本文若能对有兴趣的读者起到引
PRO*C程序移植为DBLIBRARY/C程序经验谈
刘小余
农行信用卡有关程序以前均为PRO*C程序,与Oracle(大型网站数据库平台)数据库相连。总行为与其它业务系统一致,将信用卡系统移植为SYBASE数据库下。但由此许多各行自行开发的信用卡辅助程序都面临着移植的问题。我行所采用的海通天河电话银行系统也因此不能使用。搁置达半年之久,对客户也造成了极大不便,为此,我行对此系统进行了移植,也总结了一些经验。现叙述如下,希望能对各位有所帮助。
对PRO*C程序移植为DBLIBRARY/C可分以下几个步骤:
一、 头文件的修改
由于PRO*C为在C程序中加入以EXEC SQL打头的嵌入式SQL语言,而DBL IBRARY/C则为纯C库函数的形式提供。故需提供相应的头文件。在PRO*C源程序中增加如下两行:
#include<sybdb.h>
#include<sybfront.h>
同时删去原程序中以EXEC SQL INCLUDE打头的语句,例如下格式的语句:
EXEC SQL INCLUDE SQLCA.H
二、 变量定义的修改
PRO*C中变量定义区以EXEC SQL BEGIN DECLARE打头,以EXEC SQL END DECLARE SECTION结束,而DBL IBRARY/C有自定义的变量类型。一般与PRO*C中类型有如下对应:
PRO*C DBLIBRARY/C
VARCHAR one[20] DBCHAR one[20]
float one DBFLT8 one
double one DBFLT8 one
char one[20] DBCHAR one[20]
int one DBINT one
删去以变量定义区的开始,结束两行,将其中变量按上述改为相应定义格式,同时增加两个结构指针及一个返回变量:
DBPROCESS *dbproc;
LOGINREC *dblogin;
RETCODE result_code;
三、 数据库连接的修改
PRO*C程序通过以下格式连接数据库;
strcpy(uid.str,″user″);
strcpy(pwd.str,″passwd″);
uid.len=strlen(uid.str);
pwd.len=strlen(pwd.str);
EXEC SQL CONNECT :uid IDENFITIED BY :pwd;
而DBLIBRARY/C连接方式如下:*
dbinit();
login=dblogin();
DBSETLUSER(login,″user″);
DBSETLPWD(login,″passwd″);
DBSETLAPP(login,″application_name″);
dbproc=dbopen(login,NULL);
删去原程序中PRO*C格式部分,增加DBLIBRARY/C部分。
四、 数据提取部分的修改
PRO*C一般有两种提取数据方式:
1.直接用EXEC SQL SELECT语句返回数据至变量
EXEC SQL SELECT curl,cur2 INTO :cur1,:cur2
from table
where 条件
2.用游标返回一批数据,游标如下格式定义:
EXEC SQL DECLAR cur sor_name CURSOR FOR
select cur1,cur2 from table
where条件
使用时先打开它:
EXEC SQL OPEN cursor_name
然后利用循环返回这一批量数据:
while(1)
{
EXEC SQL FETCH cursor_name into :m_curl,:m_cur2;
/*其它处理*/
…
}
最后关闭它:
EXEC SQL CLOSE cursor_name:
而DBLIBRARY/C的提取功能可一并处理上述两种方式,如下:
dbcmd(dbproc,″select cur1,cur2 from table where条件″);
dbsqlexec(dbproc);
while((result_code=dbresults(dbproc))!=NO_MORE_RESU
LTS)
{
if(result_code= SUCCEED)
{
dbbind(dbproc,1,INTBIND,(DBINT)0,(BYTE*)&m_cur1);
dbbind(dbproc,2,STRINGBIND,(DBINT)0,m_cur2);
while(dbnextrow(dbproc)!=NO_MORE_ROWS)
{
/*对数据进行处理*/
……
}
}
}
其中dbbind()函数实现字段与变量一一对应的绑定功能,所涉及到的常用变量类型有如下对应关系:
STRINGBIND DBCHAR
INTBIND DBINT
FLT8BIND DBFLT8
需注意的是:如果不为字符型数据,则dbbind()函数中,须用(BYTE*)&的方式取其地址。
五、 其它数据处理的修改
其它数据处理,如修改,删除,插入等非查询语句,
在PRO*C中,一条语句EXEC SQL…即可,
在DBL IBRARY/C中,也只需上一部分中的前两行即可:
dbcmd(dbproc,″update…″);
dbsqlexec(dbproc);
六、 数据提交与回滚的处理
PRO*C中,用如下语句:
EXEC SQL COMMIT WORK 〖RELEASE〗;
或:
EXEC SQL ROLLBACK WORK 〖RELEASE〗;
此RELEASE参数的有无决定是否提交或回滚后即退出数据连接,而DBLIBRARY/C中,则如下处理:
dbcmd(dbproc,″commit transcation″);
dbsqlexec(dbproc);
或:
dbcmd(dbproc,″rollback transcation″);
dbsqlexec(dbproc);
七、 增加退出语句
PRO*C中用数据提交或回滚即可退出。
而DBLIBRARY/C中须用专有退出函数:
dbexit();
八、 对错误与未发现情况的处理
PRO*C中通过EXEC SQL WHENEVER SQLERROR…与EXEC SQL WHENEVER NOT FOUND…实现。并在其后再定义之前一直有效。
而DBLIBRARY/C中,则为增加两个函数,并通过相应函数设为消息函数及错误函数。如下:
int msg_handler();
int err_handler();
dbmsghandle(msg_handler);
dberrhandle(err_handler);
这两个函数全局有效。msg_handler()及err_handler()函数可参考例子。另对具体数据操作过程,也可在dbsqlexec()调用后,再调用dbcount(dbproc),根据返回值(即所处理的数据行数)来确定成功与否。
九、 其它处理及编译
经过以上处理,可删除所有以EXEC SQL起头的PRO*C嵌入SQL语句及有关PRO*C特殊结构引用部分。例如:sqlca.sqlerrm.sqlerrmc等。检查整个程序,相关的PRO*C嵌入SQL语句均改为DBLIBRARY/C语句后,即可进行编译了。
cc编译命令行须加入如下参数:
-I,-I$(SYBASE)/include$(SYBASE)/lib/libsybdb.a -lnls_s-lm
其中$(SYBASE)为SYBASE系统的根目录。
十、 补充及一点经验
1.对于可变的sql语句,可用dbfcmd()代替dbcmd();
例:dbfcmd(dbproc,″select name from table where id=%d″,m_id);
2.定义相应的环境变量SYBASE,DSQYERY及正确的interfaces文件后,可访问远程的SYBASE数据库。
3.对较大的程序,如果数据分几部分存取,可分别调用dbopen()函数,返回不同的DBPROCESS结构指针,但要注意,每个指针在使用完后,要用dbclose(dbproc)关闭。
4.对于字符串变量,要注意其后的‘\0’结束符也需要占一位,定义时要比可能的最大长度大1。
5.对于字符变量,最好定义其为DBCHAR型,长度为1。
例:DBCHAR sample[1]。访问时则用sample[0]。
6.对于数据库中为日期型的字段,可利用convert()将其转为字符型输出。
例:
dbcmd(dbproc,″select convert(char(10),open_date,112)from balance″);
convert()的第三个参数决定日期转换后的格式,常用取值如下:
值 格式
2 YY.MM.DD
8 HH:MM:SS
12 YYMMDD
112 YYYYMMDD
convert()还可对其它数据类型进行转换,如欲了解详情,可参阅有关书籍。
7.PRO*C中的VARCHAR类型变量,实为一个如下的结构:
typedef struct {
char *str:
int len;
} VARCHAR;
DBLIBRARY/C中不存在此变量类型,改为DBCHAR后,相应的访问形式也须改为字符串型。
8.dbmsghandle()函数可不调用,以避免不必要的信息破坏屏幕。
9.下例也可进行sql优化,用如下sql语句代替原语句,即可不必进行循环,而直接采用第一行数据即可,由此也可见此类程序中sql优化的重要性。
select name,age,balance from table order by balance desc
为便于读者理解,实际掌握,现举例如下:
现有一数据库db,其上有一用户名为user,口令为passwd。
db中有一数据表table,其中数据如下:
name age balance
张三 26 1000.00
李四 23 956.86
王二 31 1200.00
现有一程序,实现查出工资最高的人的资料。
PRO*C程序如下(sample,pcc):
#include<stdio.h>
#include<string.h>
main()
{
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR uid[20];
VARCHAR pwd[20];
VARCHAR m_name[20];
int m_age
float m_balance;
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA.H;
EXEC SQL WHENEVER SQLERROR goto quited;
char t_name[20];
int t_age;
float t_balance=0.00;
strcpy(uid.str,″user″);
strcpy(pwd.str,″passwd″);
uid.len=strlen(uid.str);
pwd.len=strlen(uid.str);
EXEC SQL CONNECT :uid IDENFITIED BY :pwd;
EXEC SQL DECLARE CURSOR check
select name,age,balance
from table
EXEC SQL WHENEVER NOT FOUND goto continued;
/*定义查到尾造成未发现情况时跳出循环*/
EXEC SQL open check;
while(1)
{
EXEC SQL FETCH check into :m_name,:m_age,:m_balance;
if(m_balance>t_balance)
{
strcpy(t_name,m_name);
t_age=m_age;
t_balance=m_balance;
}
}
continued:
EXEC SQL CLOSE check;
printf(″%s\t%d\t%.2f ″,t_name,str,t_age,t_balance);
EXEC SQL COMMIT WORK RELASE;
exit(0);
quited:
printf(″%s″,sqlca.sqlerrm.sqlerrmc);
EXEC SQL ROLLBACK RELASE;
exit(-1);
}
改为DBLIBRARY/C程序如下(sample.c):
#include<stdio.h>
#include<string.h>
#include<sybdb.h>
#include<sybfront.h>
#define ERR_CH stderr
int err_handler();
int msg_handler();
main()
{
DBPROCESS *dbproc;
LOGINREC *login;;
RETCODE result_code;
DBCHAR m_name[20];
DBINT m_age;
DBFLT8 m_balance;
char t_name [20];
int t_age;
float t_balance=0.00;
if(dbinit()==FAIL)
exit(-1);
dberrhandle(err_handler);
dbmsghandler(msg_handler);
login=dblogin();
DBSETLUSER(login,″user″);
DBSETLPWD(login,″passwd″);
DBSETLAPP(login,″sample″);
dbproc=dbopen(login,NULL);
dbcmd(dbproc,″select name,age,balance from table″);
dbsqlexec(dbproc);
while((result_code=dbresults(dbproc))!=NO_MORE_RESU
LTS)
{
if(result_code==SUCCEED)
{
dbbind(dbproc, 1, STRINGBIND, (DBINT)0, m_name);
dbbind(dbproc,2,INTBIND,(DBINT)0,(BYTE*)&m_age);
dbbind(dbproc,3,FLT8BIND,(DBINT)0,(BYTE*)&m_balance);
while(dbnextrow(dbproc)!=NO_MORE_ROWS)
{
if(m_balance>t_balance)
{
strcpy(t_name,m_name);
t_age=m_age;
t_balance=m_balance;
}
}
}
printf(″%s\t%d\%.2f″,t_name,t_age,t_balance);
dbexit();
exit(0);
}
int err_handler(dbproc,severity,dberr,oserr,dberrstr,oserrstr)
DBPROCESS dbproc;
int severity;
int dberr;
int oserr;
char *dberrstr;
char *oserrstr;
{
if ((dbproc==NULL)‖(DBDEAD(dbproc)))
return(INT_EXIT);
else
{
fprintf (ERR_CH,″DB-Library error;\n\t%s\n″,dberrstr);
if(oserr!=DBNOERR)
fprintf (ERR_CH,″Operating-system error:\n\t%s\n″,oserrstr);
return(INT_CANCEL);
}
}
int msg_handler(dbproc,msgno,msgstate,severity,msgtext,
srvname,procname,line)
DBPROCESS * dbproc;
DBINT msgno;
int msgstate;
int severity;
char *msgtext;
char *srvname;
char *procname;
DBUSMALLINT line
{
fprintf(ERR_CH,″Msg %ld,Level %d,State %d\n″,
msgno,severity,msgstate);
if(strlen(srvname)>0)
fprintf (ERR_CH,″Server'%s',″,srvname);
if (strlen(procname)>0)
fprintf (ERR_CH,″Procedure'%s,″,procname);
if(line>0)
fprintf(ERR_CH,″Line %d″,line);
fprintf (ERR_CH,″\n\t%s\n″,msgtext);
return(0);
}
如$(SYBASE)=/u/sybase,编译命令行如下:
cc -I.-I/u/sybase/include sample.c /u/sybase/lib/libsybdb.a-lnsl_s-lm-o sample
PRO*C和DBL IBRARY/C是两种典型的数据库应用程序设计接口:一为嵌入式SQL方法,一为提供纯C函数方法。所涉及到的知识是比较庞杂的,作者也仅是略窥门径。希望本文若能对有兴趣的读者起到引门入径之作用,则吾愿足矣。
作者单位:刘小余(中国农业银行新疆自治区塔城地区分行信息电脑中心 新疆 塔城 834700)
- ››程序员 不妨都写一写前端代码
- ››proftp的防火墙配置
- ››移植Windows自宿主WCF服务到Linux/Mono2.8
- ››Prototype1.5.0 API 参考
- ››Prototype1.5 诡异错误一例
- ››Prototype : $() 的变化
- ››Prototype 的新函数 —— $$
- ››Prototype使用学习手册指南之dom.js
- ››Prototype使用学习手册指南之Selector.js
- ››Prototype使用学习手册指南之form.js
- ››prototype使用学习手册指南之event.js
- ››prototype使用学习手册指南之Position.js
更多精彩
赞助商链接