DB2数据库的sqc程序编译过程

  这里的sqc程序是指在用到db2数据库的应用程序中,sql的嵌入式C编程。在用到Oracle数据库的应用程序中,sql的嵌入式c/c++编程则是pc程序,叫做Pro*c/c++编程。
  

1 DB2的嵌入sql程序处理过程

  嵌入SQL程序处理,由一个源程序创建为一个可执行文件(或库)的过程。如下图所示:
DB2数据库的sqc程序编译过程_第1张图片

  从上图看出,首先对源文件做预编译(precompiler),生成两部分文件:一部分是纯的C程序源文件,它们和其他的C程序源文件一起,经过编译和连接生成可执行的程序(executable program);而另一部分是bind文件或package文件。bind文件经过binder操作以后,也生成为package文件。所谓package,实际上是SQL语句的访问计划。所以,预编译器将源程序中的SQL语句提出来,生成他们的访问计划,并将访问计划存放在数据库管理器中。当执行程序并遇到访问数据库的命令时,它将到数据库管理器中寻找属于它的访问计划,然后按照访问计划中所设计的方法对数据库进行访问。

具体来说:
第一步、预编译
  源程序生成以后,在源程序中嵌入了许多SQL语句,而SQL语句是宿主语言编译器所不认识的,所以在用宿主语言编译器进行编译、连接之前必须将SQL语句分离出来,这就是预编译所做的工作。DB2中预编译操作是通过PREP命令执行的,PREP命令首先将源程序中的所有有关SQL语句全部注释起来,对它进行分析和语法检查。如果源程序中的SQL语句全部书写正确,则将这些SQL语句转换成C语言可以识别的一系列的API函数。这些函数可以在函数执行时访问数据库,然后将源文件中所有用于生成数据库管理器的PACKAGE的数据提出组合成一个BIND文件。也可以直接生成一个PACKAGE,但这相当于在预编译后又执行了一次BIND操作。在预编译时,对整个源程序文件中的所有变量做统一处理而不根据变量的生命期来处理,所以宿主变量在整个程序中是唯一的。下面讲解预编译的步骤:
1)、连接到一个数据库,该操作是为BIND做准备。操作如下:
  db2 connect to cicstest
2)、执行预编译命令,假设源文件为adhoc.sqc,则:
  db2 prep adhoc.sqc bindfile

下面我们对预编译的几种输出文件进行讨论。
  预编译后生成的C语言源文件:该文件中原有的SQL语句,已经全部加上注释并转换成了C语言可以识别的API调用。
  BIND文件:如果在预编译时使用BINDFILE选项,则生成BIND文件,BIND文件的后缀为.bnd,BIND文件可以在将来使用BIND命令来生成PACKAGE。
    db2 bind adhoc.bnd
  如果在预编译时,只生成BIND文件,那么即使在预编译时,不能访问某些数据库对象,系统也只是报警,而不会报错。如果使用PACKAGE选项,则生成PACKAGE。如果有MESSAGE选项,则生成信息文件,它包含了所有的返回信息,如:警报、错误等。它便于程序员对源程序做进一步的修改。

第二步、编译和连接
  在预编译后,程序中只有C语言语句,它们都可以为C语言的编译器所识别。所以,可以按照一般的方法进行编译和连接,但在将SQL语句转换以后,在C语言程序中,又引入了许多一般的C语言系统所没有的INCLUDE文件和函数库,这些均在DB2的SDK中。所以,要生成可执行的程序,就必须安装DB2的SDK,并且做以下设置:
  set INCLUDE=$(DB2PATH)\include;%include%
  set LIB=$(DB2PATH)\lib;%LIB%
下面是编译和连接:
cl -o adhoc.exe adhoc.c
生成的可执行文件必须与数据库管理器中的PACKAGE相结合,才能执行。

下面对BIND做进一步解释。
  PACKAGE是DB2为SQL语句制定的访问计划。通过precompile之后,源程序中的SQL语句部分就被分离出来。PACKAGE就是根据具体的SQL语句和数据库中的信息生成的针对每条SQL语句的访问计划,它存放在DB2数据库服务器上。应用程序执行到SQL语句时,就到相应的服务器上去找它们的PACKAGE,数据库服务器根据PACKAGE执行具体的数据库操作。所以,如果一个应用程序访问了多个数据库服务器,则该应用程序应在它访问到的数据库服务器上均生成相应的PACKAGE。因此,当遇到这种情况时,推荐的方式是将源程序分成若干个文件,每个文件只访问一个服务器,然后分别进行预编译。
  执行PREP命令时,加上选项PACKAGE或不注明BINDFILE、SYNTAX或SQLFLAG选项,这时BIND操作将自动进行。直接使用BIND命令从BIND文件中生成PACKAGE存放在数据库管理器中。BIND完成的功能是,从数据库中找到SQL语句所涉及的表,查看SQL语句中提到的表名及属性是否与数据库中的表名和属性相匹配,以及应用程序开发者是否有权限查询或修改应用程序中所涉及到的表及属性。这就是为什么在预编译之前要连接到相应的数据库上的原因。在做BIND操作后,在数据库管理器中就生成一个PACKAGE,PACKAGE的名字与源程序的文件名字相同。
  一个源文件在数据库中可有多个PACKAGE存在。为了区分不同的PACKAGE,DB2中引入了时间戳的概念。在PREP执行时,系统对生成的修改过的C语言程序和BIND文件以及PACKAGE中都加入了一个时间戳。BIND文件在生成PACKAGE时也将时间戳传递下来,修改过的C语言程序在生成可执行程序时,同样也将时间戳传递下去。当应用程序运行时,可执行程序是通过时间戳找到相应的PACKAGE,如果时间戳不匹配,则说明版本更新,需要做BIND。

总之,一个sqc程序编译的过程大致如下:
1、编辑好sqc文件(如:test.sqc);
2、连接数据库:db2 connect to $DBLINK;
3、调用DB2的prep命令对sqc文件进行预编译,用来生成C文件;
  db2 prep test.sqc BINDFILE package using bindtest
说明:
上述命令中的“BINDFILE”是用来指定在做预编译的同时生成bind文件的(如:bindtest.bnd);上述命令中的“package using bindtest”是用来指定将要写入到DB2的系统表中的package信息的名称(如:bindtest)。bind文件里记载的是用来写入到package信息的数据。
4、调用DB2的bind 命令从上一步生成的bind文件中读出必要的数据写入到上一步指定名称的package信息中。并可以给这条信息指定访问权限。
  db2 bind bindtest.bnd GRANT PUBLIC
5、到目前为止可以说与DB2相关的所有预编译就基本完成了,我们需要的C文件(如:test.c)也生成了,那个bind文件后边暂时不会用到了。下来就可以调用gcc编译器对这个C文件进行编译,基本的过程是test.c→test.o→test。这样我们就可以执行这个最终的可运行程序了。

2 编译sqc程序的makefile

某实例sqc程序的编译makefile:

#|----------------------------------------------------------------------------|
#|                           TOPMake 2.0                                      |
#| Copyright (c) 2000-2003 xxx Software Systems Co., Ltd.        |
#|    All Rights Reserved                                                     |
#|----------------------------------------------------------------------------|
#| FILE NAME    : makefile                                                    |
#| DESCRIPTIONS : makefile for dynamic library                                 |
#|----------------------------------------------------------------------------|

PRGOBJS = \
    xxx.o

PRGTARG = xxx
PRGLIBS = $(UXLIBS) $(DBLIBS)
PRGDEFS =

# used for db2 database
PRGDBNM = $(DBLINK)

debug all: debugdynamic
release: releasedynamic
#debug all: debugstatic
#release: releasestatic

# DO NOT modify any code below!!!

releasedynamic debugdynamic releasestatic debugstatic releaseexec debugexec clean:
    @make -f $(FEHOME)/mak/mkstand.mak $@ TARGET="$(PRGTARG)" OBJS="$(PRGOBJS)" LIBS="$(PRGLIBS)" DEFS="$(PRGDEFS)" DBNM="$(PRGDBNM)"

总的makefile,这里只截取部分,只需明白步骤即可:

.sqc.o:
    $(ECHO) "Compiling [$@] ..."
    @$(RM) $*.bnd
    @$(DB2) connect to $(DBNM)
    @DB2INCLUDE=$(INCP) \
    $(DB2) prep $< bindfile LONGERROR NO
    @$(DB2) bind $*.bnd
    @$(DB2) connect reset
    @$(DB2) terminate
    @$(CD) `dirname $@` ; \
    $(CC) -o $@ `cat $(FEHOME)/mak/.mak.tmp` $(CCFLGS) -c `basename $*`.c
    @$(MV) $*.bnd $(FEHOME)/bnd/
    @$(RM) $*.

你可能感兴趣的:(数据库)