分类: 数据库开发技术
2009-08-26 11:11:21
ESQL/C(Embedded SQL,即嵌入式SQL)使得C程序员可以将SQL语句直接嵌入C程序。任何可交互输入的SQL语句都可用于C程序中,但有些可用于C程序中的SQL语句却不能用于交互模式。关于ESQL的规则主要有:
☆ 给SQL语句加上EXEC SQL前缀,以此来区分ESQL语句和普通C语句。ESQL语句也以“;”结束。
☆ 可执行的ESQL语句可放在任何可执行C语句能够出现的地方。
☆ ESQL语句前缀既可以大写,也可以小写,但为了使ESQL语句与普通C语句有明显区别,建议使用大写的前缀。
☆ 除了变量申明外,几乎每一个ESQL语句后都应检查SQLCODE的值。该值为0表示成功执行了ESQL语句,若小于0表示执行ESQL语句时出错,大于0通常表示一个警告信息。对于informix数据库,可以在shell里使用命令
finderr [errno]
来获取错误信息。
主变量是一般的C变量,其间的区别仅在于主变量既可用于ESQL语句,也可用于普通C语句,而一般的C变量则只能用于普通C语句。主变量必须申明在下列两个语句之间:
EXEC SQL BEGIN DECLARE SECTION;
EXEC SQL END DECLARE SECTION;
在ESQL语句中使用主变量时,必须加前缀“:”(冒号)。在普通C语句中使用主变量与一般C变量的用法相同。例如,下例定义主变量更改保证金帐户的余额:
int UpdateEacc(char *accno, double bal)
{
EXEC SQL BEGIN DECLARE SECTION;
char ea_accno[17];
double ea_eamt;
EXEC SQL END DECLARE SECITON;
strcpy (ea_accno, accno);
ea_eamt = bal;
EXEC SQL UPDATE ca_eacc SET ea_eamt = :ea_eamt
WHERE ea_accno = :ea_accno;
if (SQLCODE < 0) /* some error occurs */
{
printf (“[%s--%ld], fail to update[%d]\n”,
__FILE__, __LINE__, SQLCODE);
return (-1);
}
return (0);
}
通用语法:
INTO var-list
FROM [OUTER] table-name [table-alias] [,...]
[WHERE condition]
[GROUP BY column-list] [HAVING condition]
[ORDER BY column-name [ASC | DESC],...]
[INTO TEMP table-name] [WITH NO LOG]
该语句适用于已知结果集只有一条记录的查询。如果通过此语句得到的结果集包含多条记录,则SQLCODE会置成一个负数来指示错误。
如果某一字段可能为空值(NULL),则应该为此字段指定一个指示器变量,查询执行后,若该指示器变量小于0,则此字段为空值。例如,下例查询保证金分户帐的利息,如果利息为空值则认为等于0:
int get_int(char *accno, double *int)
{
EXEC SQL BEGIN DECLARE SECTION;
char ea_accno[17];
double ea_enterest;
int ea_enterest_i; /* indicator */
EXEC SQL END DECLARE SECTION;
strcpy (ea_accno, accno);
ea_enterest_i = 0;
EXEC SQL SELECT ea_enterest INTO :ea_enterest :ea_enterest_i
FROM ca_eacc
WHERE ea_accno = :ea_accno;
if (SQLCODE)
{
printf (“[%s--%ld], fail to select[%d--%s]\n”,
__FILE__, __LINE__, SQLCODE, accno);
return (-1);
}
if (ea_enterest_i < 0) ea_enterest = 0;
*int = ea_enterest;
return (0);
}
通用语法:
EXEC SQL UPDATE table-name SET {column-name = variable [,...]
| {(col-list) | *} = (var-list)}
[WHERE condition]
EXEC SQL INSERT INTO table-name [(column-list)]
{
VALUES (var-list)
|
SELECT-statement
}
EXEC SQL DELETE FROM table-name [WHERE condition]
如果结果集可能包含多条记录,则应该使用游标(CURSOR)来执行查询。使用游标的步骤通常如下所示:
☆ 申明游标
☆ 打开游标
☆ 推进游标,读取记录
☆ 关闭游标
下例从保证金分户帐中读取机构代码为5210642188的所有帐户的帐号、帐户名称及余额:
int PrintEacc(char *org)
{
EXEC SQL BEGIN DECLARE SECTION;
char ea_org[11];
char ea_accno[17];
char ea_name[11];
double ea_eamt;
int ea_eamt_i;
EXEC SQL END DECLARE SECTION;
/* 申明游标 */
EXEC SQL DECLARE eacc_cur CURSOR FOR
SELECT ea_accno, ea_name, ea_eamt
FROM ca_eacc
WHERE ea_org = :ea_org;
if (SQLCODE)
{
printf (“[%s--%ld], fail to declare cursor[%d]\n”,
__FILE__, __LINE__, SQLCODE);
return (-1);
}
/* 设置机构代码并打开游标 */
strcpy (ea_org, org);
EXEC SQL OPEN eacc_cur;
if (SQLCODE)
{
printf (“[%s--%ld], fail to open cursor[%d--%s]\n”,
__FILE__, __LINE__, SQLCODE, org);
return (-1);
}
while (1)
{
/* 设置初值 */
memset (ea_accno, ‘\
memset (ea_name, ‘\
ea_eamt = ea_eamt_i = 0;
/* 推进游标 */
EXEC SQL FETCH eacc_cur INTO
:ea_accno, :ea_name, :ea_eamt :ea_eamt_i;
if (SQLCODE == SQLNOTFOUND) break; /* 结果集末尾 */
if (SQLCODE)
{
printf (“[%s--%ld], fail to fetch cursor[%d--%s]\n”,
__FILE__, __LINE__, SQLCODE, org);
EXEC SQL CLOSE eacc_cur; /* 关闭游标 */
EXEC SQL FREE eacc_cur; /* 释放游标资源 */
return (-1);
}
if (ea_eamt_i < 0) ea_eamt = 0;
printf (“accno[%s], name[%s], amount[%16.2lf]\n”,
ea_accno, ea_name, ea_eamt);
}
EXEC SQL CLOSE eacc_cur; /* 关闭游标 */
EXEC SQL FREE eacc_cur; /* 释放游标资源 */
return (0);
}
EXEC SQL DATABASE dabase-name;
EXEC SQL CLOSE DATABASE;
ESQL源程序通常以.ec做为后缀,通过编译选项的选择,ESQL编译器可将.ec源代码预处理成.c源程序(-e),或者编译成.o文件(-c),或者编译链接成可执行文件(默认)。例如,如下的makefile和包含文件可将指定的文件编译成可执行代码:
包含文件:
# makefile header
TRANHOME=/home/credit/transform
TRANBIN=$(TRANHOME)/bin
OBJPATH= $(TRANHOME)/obj
# compiler
CC= xlc_r4
CC= cc
ESQL= esql
# flags
PREFLAG= -g -DDEBUGON
LINKFLAGS=-g -DDEBUGON -static
# libarary
LIB=-lFit -lsql -lcurses -lc -ldl -lreportall
# path
LIBDIR=-L. -L$(TRANHOME)/lib \
-L${INFORMIXDIR}/lib/esql -L${INFORMIXDIR}/lib
INCLUDE= -I${TRANHOME}/include -I${INFORMIXDIR}/incl \
-I${INFORMIXDIR}/incl/esql
OBJ=$(EC_SRC:.ec=.o) $(C_SRC:.c=.o)
EXEC=$(SC_SRC:.sc=.exe)
# rule
.SUFFIXES: .ec .o .sc .exe .c .o
.c.o:
@echo "\tcompiling " $< "\t....................\c"
@$(CC) -c $(PREFLAG) $(INCLUDE) $*.c
@echo "OK"
.ec.o:
@echo "\tcompiling " $< "\t....................\c"
@$(ESQL) -e $(PREFLAG) $(INCLUDE) $<
@$(CC) -c $(PREFLAG) $(INCLUDE) $*.c
@rm -f $*.c
@echo "OK"
.sc.exe:
@echo "\tcompiling " $< "\t....................\c"
@cp $< $*.ec
@$(ESQL) -e $(PREFLAG) $(INCLUDE) $*.ec
@$(ESQL) -c $(PREFLAG) $(INCLUDE) $*.c
@$(ESQL) $(LINKFLAGS) ${INCLUDE} -o $@ $*.o \
$(FOREIGNOBJ) $(LIBDIR) ${LIB}
@cp $*.exe $*
@rm -f $*.ec $*.c $*.o
@echo "OK"
# rule
all:$(OBJ) $(EXEC)
@echo "\t\tdoing with object file\t\t............\c"
@if [ "$(OBJ)" != " " ] ; then \
chmod 644 $(OBJ) ; \
cp $(OBJ) $(OBJPATH) ; \
fi
@echo "OK"
@echo "\t\tdoing with executable file\t............\c"
@for varible in $(SC_SRC:.sc=) null_file ; \
do \
if test -f $$varible ; then \
chmod 755 $$varible ; \
mv $$varible $(TRANBIN) ; \
fi; \
done
@echo "OK"
clean:
@echo "\tremoving files\t....................\c"
@rm -f $(C_SRC:.c=.o) $(EC_SRC:.ec=.o) $(EC_SRC:.ec=.c)
@rm -f $(SC_SRC:.sc=.o) $(SC_SRC:.sc=.c) $(SC_SRC:.sc=.ec)
@rm -f $(SC_SRC:.sc=.exe) $(SC_SRC:.sc=)
@echo "OK"
makefile文件:
# file list
EC_SRC= tp_main.ec
SC_SRC= tp_acctyp.sc tp_cardacc.sc tp_cardproc.sc \
tp_cardser.sc tp_eacc.sc tp_iacc.sc \
tp_idetail.sc tp_kbacc.sc \
tp_ointer.sc tp_procacc.sc tp_subject.sc tp_sys.sc
C_SRC=
include ../mkhead