Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2207554
  • 博文数量: 1058
  • 博客积分: 10018
  • 博客等级: 上将
  • 技术积分: 12641
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-23 19:24
文章分类

全部博文(1058)

文章存档

2010年(108)

2009年(736)

2008年(214)

我的朋友

分类: C/C++

2008-11-18 00:45:40

ESQLC移植到PROC第二版
 
本文档讲述数据库嵌入式SQL/C语言程序从ESQLC向PROC移植过程中所进行的分析、移植过程,并讲述如何编写可通用的嵌入式SQL/C语言程序。
 
第一部分: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数据库
 */
 
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数据库
 */
 
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
#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
#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即可。
阅读(1961) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~