本文档讲述数据库嵌入式
SQL/C语言程序从ESQLC向PROC移植过程中所进行的分析、移植过程,并讲述如何编写可通用的嵌入式SQL/C语言程序。
作者:余军,
2007年5月9日
第一部分:ESQLC,PROC差异性分析
一.基本语法
1.语法字符
ESQLC中既支持‘
$’数据库语法,同时也支持“EXEC SQL”,‘:’数据库语法
PROC中只支持“
EXEC SQL”,‘:’数据库语法
2.数据库变量定义
ESQLC中支持
3种表达方法
方法
1,
$int nValue;
$char strValue[20];
方法
2(会有警告,但不影响编译及运行结果),
EXEC SQL int nValue;
EXEC SQL char strValue[20];
方法
3,
EXEC SQL BEGIN DECLARE SECTION;
int nValue;
char strValue[20];
EXEC SQL END DECLARE SECTION;
PROC中支持
2种表达方法
方法
1,不加任何修饰,即与非数据库变量的定义相同
方法
2,
EXEC SQL BEGIN DECLARE SECTION;
int nValue;
char strValue[20];
EXEC SQL END DECLARE SECTION;
3.数据库变量的使用
ESQLC中对‘
$’,‘:’均能支持
PROC中只能用‘
:’
4.基本的SQL语句(查询、插入、删除、修改)
ESQLC,
sql语句中可以用数据库变量,也可以用常量,如where name= '张三'
PROC,
sql语句中只能用数据库变量,如where name= :m_name
二.高级SQL操作(游标等)
1.数据库打开、关闭操作
ESQLC中打开数据库使用
database 数据库名,关闭数据库使用database close
PROC中打开数据库使用
CONNECT :username IDENTIFIED BY :password,不用关闭
2.事务操作
ESQLC中语法
打开事务,
begin work;
提交事务,
commit work;
回滚事务,
rollback work;
PROC中语法
打开事务,不写
提交事务,
commit work;
回滚事务,
rollback;
3.游标操作
游标基本语法
定义游标,
declare cur名称 cursor for sql语句
打开游标,
open cur_1或open cur_1 using :con1,:con2
Fetch游标,
fetch cur_1或fetch cur_1 into :val1,:val2
关闭游标,
close cur_1
释放游标,
free cur_1
两平台区别:
sql语句区别同基本
sql语句,PROC中不能用用常值(where name= '张三'),只能用数据库变量(where name= :m_name)。
PROC中不能释放游标,而
ESQLC中要求释放游标。
三.数据库操作运行结果
1.表达符
ESQLC中一般采用
SQLCODE,也可采用sqlca.sqlcode
PROC中只能用
sqlca.sqlcode。
2.常用数值含义
开发阶段
含义
|
Informix,
ESQL/C
|
Oracle,
PROC
|
插入时列数不匹配
|
-236
|
(待查)
|
字段不存在
|
-217
|
(待查)
|
运行阶段
含义
|
Informix,
ESQL/C
|
Oracle,
PROC
|
找到数据
|
0
|
0
|
找不到数据
|
100
|
1403
|
插入时重复
|
-239
|
-1
|
找到记录不唯一
|
(待查)
|
(待查)
|
范围超限
|
(待查)
|
1480
|
找到值为
NULL
|
(待查)
|
-1405
|
其他(待续)
|
|
|
四.程序的编译及链接
1.基本命令
ESQLC预编译命令
esql
PROC预编译命令
proc
2.编译语法
ESQLC中
makefile的一般写法
CC=cc
ECC=$(INFORMIXDIR)/bin/esql
.SUFFIXES:.ec
.SUFFIXES:.c
.ec.o:
$(ECC) -c $*.ec
rm -f $*.c
.c.o:
$(CC) -c $*.c
PROC中
makefile的一般写法
CC=cc
PROC=proc userid=用户名
/密码 sqlcheck=full char_map=string
INCLUDE=头文件目录
CFLAGS=编译参数
.SUFFIXES:.c
.SUFFIXES:.pc
.pc.o:
$(PROC) $(INCLUDE) iname=$*.pc oname=$*.c
$(CC) -I$(INCLUDE) $(CFLAGS) -c -o $*.o $*.c
rm -f $*.c
rm -f $*.lis
.c.o:
$(CC) -I$(INCLUDE) $(CFLAGS) -c -o $*.o $*.c
3.链接语法
ESQLC中,
$(ECC) -o 可执行文件 链接文件1 连接文件2 …
PROC中,
$(CC) -o 可执行文件 链接文件1 连接文件2 …
其中链接文件,可以事
obj文件,静态库文件,源文件等。
第二部分:移植步骤
不同风格的
ESQLC程序,采用不同的移法,总之越接近PROC,则越容易移植,这里讲述与PROC风格相差最大的ESQLC程序(采用‘$’作为数据库操作标识符)的移植方法。
一.程序移植
编辑工具采用
UltraEdit,应用多文件替换操作。
1.程序修改
步骤
1,先修改操作语句,即将‘$’修改“EXEC SQL ”
Informix,
ESQL/C
|
Oracle,
PROC
|
"$select "
|
"EXEC SQL select "
|
"$insert "
|
"EXEC SQL insert "
|
"$update "
|
"EXEC SQL update "
|
"$delete "
|
"EXEC SQL delete "
|
"$prepare "
|
"EXEC SQL prepare "
|
"$declare "
|
"EXEC SQL declare "
|
"$open "
|
"EXEC SQL open "
|
"$fetch "
|
"EXEC SQL fetch "
|
"$close "
|
"EXEC SQL close "
|
"$free "
|
"EXEC SQL free "或
"free_cursor()"
|
"$begin work"
|
"EXEC SQL begin work"或
"begin_work()"
|
"$commit work"
|
"EXEC SQL commit work"
|
"$rollback work"
|
"EXEC SQL rollback"或
"rollback_work()"
|
"$database "
|
"EXEC SQL database "或
"open_database()"
|
步骤
2,将剩下的‘$’全部替换成‘:’
步骤
3,手工修改各数据库变量定义部分
步骤
4,将打开数据库语句更新成open_database()
步骤
5,编写相应的函数open_database(),free_cursor(),begin_work(),rollback_work()等,函数实体程序根据相应数据库平台的语法即可。
步骤
6,在公共头文件中宏定义#define SQLCODE sqlca.sqlcode
步骤
7,用PROC的makefile文件,进行重新编译,再细微调整错误的地方。
2.Makefile文件的编写
步骤
1,更改相应的编译变量
$(CC)也改成相应环境下的
C编译器
$(ECC)=xxx改成
$(PROC)=xxx
步骤
2,修改.ec到.o的编译方法
.ec.o:
$(PROC) $(INCLUDE) iname=$*.ec oname=$*.c
$(CC) -I$(INCLUDE) $(CFLAGS) -c -o $*.o $*.c
rm -f $*.c
rm -f $*.lis
步骤
3,修改连接方法
将
$(ECC)修改成$(CC)。
二.数据库移植
1.表结构的移植
软件工具
powdesinger
步骤
1,利用反向工程,从原来的INFORMIX数据库中生成PDM图表文件
步骤
2,更改当前数据库连接,新的连接为ORACLE数据库
步骤
3,生成SQL语句。
步骤
4,将该SQL语句在ORACLE环境中执行即可。
2.数据的移植
不同的数据库之间,采用文本文件移植较为安全
步骤
1,从INFORMIX库中导出所有表,可以用dbexport,也可以用shell文件执行unload to xx.txt select * from xx表
步骤
2,将文本文件传到可以导入ORACLE的位置。
步骤
3,编写ORACLE的sqlldr控制文件,执行即可。
第三部分:如何编写两个平台通用的C程序
在项目实施过程中,一个产品往往流程完全一致,但不同的客户可能数据库平台有区别,作为软件开发商或供应商,如果同时提供两个版本,很容易造成版本不统一,加大了维护成本,所以必须找到一个方法使两个版本程序能尽可能的复用。经过本人的实践,最后做出只需要修改一个宏定义,就可以实现程序在两个平台间的共用。
1.程序文件名的统一
ESQLC中只支持扩展名
=ec的ESQLC程序,而PROC中可支持任意扩展名的PROC程序,所以我们将程序名称统一成xxx.ec
2.数据库公共宏定义
/*
#define DB_IS_INFORMIX
*/
#define DB_IS_ORACLE
#ifdef DB_IS_INFORMIX
#define SQL_DATA_FIND 0
#define SQL_NO_DATA_FIND 100
#else
#define SQL_DATA_FIND 0
#define SQL_NO_DATA_FIND 1403
#endif
3.部分数据库公共操作函数
EXEC SQL include sqlca;
//打开数据库
int open_database()
{
EXEC SQL BEGIN DECLARE SECTION;
char username[50];
char password[50];
EXEC SQL END DECLARE SECTION;
memset(username, 0, sizeof(username));
memset(password, 0, sizeof(password));
strcpy(username, "数据库用户名");
strcpy(password, "数据库用户密码");
#ifdef DB_IS_INFORMIX
EXEC SQL database 数据库库名;
#else
EXEC SQL connect :username identified by :password;
#endif
}
//开始事务
int begin_work()
{
#ifdef DB_IS_INFORMIX
EXEC SQL begin work;
if(sqlca.sqlcode){
printf("begin_work error:%d/n", sqlca.sqlcode);
return -1;
} else{
return 0;
}
#else
return 0;
#endif
}
//回滚事务
int rollback_work()
{
#ifdef DB_IS_INFORMIX
EXEC SQL rollback work;
#else
EXEC SQL rollback;
#endif
if(sqlca.sqlcode){
printf("rollback_work error:%d/n", sqlca.sqlcode);
return -1;
} else{
return 0;
}
}
结束!