从
ESQLC移植到PROC第二版
本文档讲述数据库嵌入式
SQL/C语言程序从ESQLC向PROC移植过程中所进行的分析、移植过程,并讲述如何编写可通用的嵌入式SQL/C语言程序。
作者:余军,
2007年
5月9日,初版,完成差异性分析,移植步骤、通用程序说明。
2007年
5月21日,修订,对差异性分析增加数据类型的说明,并增加编写了详细的程序代码及
Makefile文件。
第一部分: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
5.数据库变量的数据类型
ESQLC中不支持
unsigned类型,对typedef支持也不是很好,虽然在sys/types.h中已经有类型定义,但还是要在程序中再次定义,且必须定义在BEGIN DECLARE/END DECLARE之间
PROC中能够支持
unsigned类型,也支持typedef,即在sys/types.h中定义的都能够使用
二.高级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) $(INCL_FLAG) $(CFLAGS_1) -c -o $*.o $*.ec
rm -f $*.c
.c.o:
$(CC) $(INCL_FLAG) $(CFLAGS_1) -c -o $*.o $*.c
PROC中
makefile的一般写法
CC=cc
PROC=proc userid=用户名
/密码 sqlcheck=full char_map=string
.SUFFIXES:.pc
.SUFFIXES:.c
.pc.o:
$(PROC) $(INCL_FLAG2) iname=$*.pc oname=$*.c
$(CC) $(INCL_FLAG) $(CFLAGS_1) -c -o $*.o $*.c
rm -f $*.c
rm -f $*.lis
.c.o:
$(CC) $(INCL_FLAG) $(CFLAGS_1) -c -o $*.o $*.c
其中:
INCL_FLAG=链接头文件目录
CFLAGS_1=编译参数,如
-q64表示编译成64位,-qcpluscmt表示支持//单行注释
3.链接语法
ESQLC中,两种方法
$(ECC) -o 可执行文件 应用链接文件
1 应用链接文件2 …
或者
$(CC) -o 可执行文件应用链接文件1 应用链接文件2 及Informix静态链接库(可通过esqql –libs获知该连接那些库文件,另外再加上$(INFORMIXDIR)/lib/checkapi.o)
PROC中,
$(CC) -o 可执行文件 应用链接文件1 应用链接文件2 及Oracle静态链接库(可通过cat $ORACLE_HOME/lib/sysliblist 获知应该链接那些库文件,另外要加上-lclntsh)
其中链接文件,可以是
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()"
|
"$close database "
|
"EXEC SQL database "或
"close_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) $(INCL_FLAG2) iname=$*.ec oname=$*.c
$(CC) $(INCL_FLAG) $(CFLAGS_1) -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程序
在项目实施过程中,一个产品往往流程完全一致,但不同的客户可能数据库平台有区别,作为软件开发商或供应商,如果同时提供两个版本,很容易造成版本不统一,加大了维护成本,所以必须找到一个方法使两个版本程序能尽可能的复用。经过本人的实践,最后采用以下
3个不同的宏定义或文件实现程序在两个平台间的共用。
a.
DB_IS_INFORMIX/DB_IS_ORACLE等宏定义
b.
db_ifx.ec/db_ora.ec数据库操作
c.
mk.ifx/mk.ora编译用的make文件
一.程序文件名的统一
ESQLC中只支持扩展名
=ec的ESQLC程序,而PROC中可支持任意扩展名的PROC程序,所以我们将程序名称统一成xxx.ec
二.数据库公共宏定义
/*
#define DB_IS_INFORMIX
*/
#define DB_IS_ORACLE
#ifdef DB_IS_INFORMIX
#define SQL_DATA_FIND 0
#define SQL_NO_DATA_FIND 100
#define SQL_DUPLICATE -239
#define SQL_ORA_ERROR -1405
#else
#define SQL_DATA_FIND 0
#define SQL_NO_DATA_FIND 1403
#define SQL_DUPLICATE -1
#define SQL_ORA_ERROR -1405
#endif
#define SQLCODE sqlca.sqlcode
#注意:
SQLCODE也可以不再这里宏定义,在
proc编译选项中,缺省情况def_sqlcode=no,如果设置def_sqlcode=yes,则proc自己能进行该宏定义操作。
DB_IS_INFORMIX/DB_IS_ORACLE也可以不在此处定义,在
cc编译选项中设置-D DB_IS_INFORMIX或-D DB_IS_ORACLE即可。
三.数据库公共操作函数及源文件
1.程序文件db_ifx.ec
/*
*文件
:db_ifx.ec
*描述
:用于处理INFORMIX数据库
*作者
:YuJun,2007.05.10
*/
EXEC SQL include sqlca;
/*打开数据库
*/
int open_database(void)
{
EXEC SQL database devp_jxnc;
if(sqlca.sqlcode){
printf("open_database error:%d/n", sqlca.sqlcode);
return -1;
} else{
return 0;
}
}
/*关闭数据库
*/
void close_database(void)
{
EXEC SQL close database;
}
/*开始事务
*/
int begin_work(void)
{
EXEC SQL begin work;
if(sqlca.sqlcode){
printf("begin_work error:%d/n", sqlca.sqlcode);
return -1;
} else{
return 0;
}
}
/*回滚事务
*/
int rollback_work(void)
{
EXEC SQL rollback work;
if(sqlca.sqlcode){
printf("rollback_work error:%d/n", sqlca.sqlcode);
return -1;
} else{
return 0;
}
}
/*释放游标
*/
void free_cursor(void)
{
return;
}
|
2.程序文件db_ora.ec
/*
*文件
:db_ora.ec
*描述
:用于处理ORACLE数据库
*作者
:YuJun,2007.05.10
*/
EXEC SQL include sqlca;
/*打开数据库
*/
int open_database(void)
{
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, "posp");
strcpy(password, "posp");
EXEC SQL connect :username identified by :password;
if(sqlca.sqlcode){
printf("open_database error:%d/n", sqlca.sqlcode);
return -1;
} else{
return 0;
}
}
/*关闭数据库
*/
void close_database(void)
{
return;
}
/*开始事务
*/
int begin_work(void)
{
return 0;
}
/*回滚事务
*/
int rollback_work(void)
{
EXEC SQL rollback;
if(sqlca.sqlcode){
printf("rollback_work error:%d/n", sqlca.sqlcode);
return -1;
} else{
return 0;
}
}
/*释放游标
*/
void free_cursor(void)
{
return;
}
|
四.Makefile文件的编写
1.编译文件mk.ifx
#Makefile for informxi/oracle
#Write by YuJun. 2007.05.21
#no tuxedo env
#1.定义公共
make变量
APPDIR=$(HOME)
DB_HOME=$(INFORMIXDIR)
BIN_DIR=$(APPDIR)/bin
#2.定义
informix/oracle数据库相关的make变量
#2.1 informix下的
make变量设置
INCL_DB=$(DB_HOME)/incl/esql
DB_OBJ=db_ifx.o
DBLIB=$(INFORMIXDIR)/lib/esql/checkapi.o -L$(INFORMIXDIR)/lib/esql -L$(INFORMIXDIR)/lib -lixsql -lixasf -lixgen -lixos -lixgls -lnsl_s -lcrypt_i -lsocket -lm -lsuds -lx
ECC=esql
CFLAGS_1=-DDB_IS_INFORMIX
CFLAGS_2=
#informix.设置
.end
#2.2 oracle下的
make变量设置
#INCL_DB=$(DB_HOME)/precomp/lib
#DB_OBJ=db_ora.o
#DBLIB=-L$(ORACLE_HOME)/lib -lm -lclntsh
#PROC=proc userid=posp/posp sqlcheck=full char_map=string def_sqlcode=yes
#CFLAGS_1=-q64 -qcpluscmt -DDB_IS_ORACLE
#CFLAGS_2=-q64
#oracle.设置
.end
#3.CC变量及
include
CC=cc
INCL_APP=$(APPDIR)/incl
INCL_TUXEDO=$(TUXDIR)/include
INCL_FLAG=-I$(INCL_APP) -I$(INCL_DB)
INCL_FLAG2=include=$(INCL_APP) include=$(INCL_DB)
#4.应用依赖的
OBJ设置
clean:
rm -f *.o
TESTAPP=mylib.o #等等
testapp:testapp.o $(LIB_TESTAPP) $(DB_OBJ)
$(CC) $(CFLAGS_2) -o $@ $? /
$(DBLIB)
mv $@ $(BIN_DIR)
.SUFFIXES:.c
.SUFFIXES:.ec
.ec.o:
$(ECC) $(INCL_FLAG) $(CFLAGS_1) -c -o $*.o $*.ec
rm -f $*.c
.c.o:
$(CC) $(INCL_FLAG) $(CFLAGS_1) -c -o $*.o $*.c
|
2.编译文件mk.ora
#Makefile for informxi/oracle
#Write by YuJun. 2007.05.21
#no tuxedo env
#1.定义公共
make变量
APPDIR=$(HOME)
DB_HOME=$(ORACLE_HOME)
BIN_DIR=$(APPDIR)/bin
#2.定义
informix/oracle数据库相关的make变量
#2.1 informix下的
make变量设置
#INCL_DB=$(DB_HOME)/incl/esql
#DB_OBJ=db_ifx.o
#DBLIB=$(INFORMIXDIR)/lib/esql/checkapi.o -L$(INFORMIXDIR)/lib/esql -L$(INFORMIXDIR)/lib -lixsql -lixasf -lixgen -lixos -lixgls -lnsl_s -lcrypt_i -lsocket -lm -lsuds -lx
#ECC=esql
#CFLAGS_1=-DDB_IS_INFORMIX
#CFLAGS_2=
#informix.设置
.end
#2.2 oracle下的
make变量设置
INCL_DB=$(DB_HOME)/precomp/public
DB_OBJ=db_ora.o
DBLIB=-L$(ORACLE_HOME)/lib -lm -lclntsh
PROC=proc userid=posp/posp sqlcheck=full char_map=string def_sqlcode=yes
CFLAGS_1=-q64 -qcpluscmt -DDB_IS_ORACLE
CFLAGS_2=-q64
#oracle.设置
.end
#3.CC变量及
include
CC=cc
INCL_APP=$(APPDIR)/incl
INCL_TUXEDO=$(TUXDIR)/include
INCL_FLAG=-I$(INCL_APP) -I$(INCL_DB)
INCL_FLAG2=include=$(INCL_APP) include=$(INCL_DB)
#4.应用所依赖的
OBJ设置等
clean:
rm -f *.o
TESTAPP=mylib.o #等等
testapp:testapp.o $(LIB_TESTAPP) $(DB_OBJ)
$(CC) $(CFLAGS_2) -o $@ $? /
$(DBLIB)
mv $@ $(BIN_DIR)
.SUFFIXES:.c
.SUFFIXES:.ec
.ec.o:
$(PROC) $(INCL_FLAG2) iname=$*.ec oname=$*.c
$(CC) $(INCL_FLAG) $(CFLAGS_1) -c -o $*.o $*.c
rm -f $*.c
rm -f $*.lis
.c.o:
$(CC) $(INCL_FLAG) $(CFLAGS_1) -c -o $*.o $*.c
|
注:在使用时,根据环境,将其中的一个拷贝成
Makefile即可。
结束!