DB2數據庫的sqc程序編譯過程

  這裏的sqc程序是指在用到db2數據庫的應用程序中,sql的嵌入式C編程。在用到Oracle數據庫的應用程序中,sql的嵌入式c/c++編程則是pc程序,叫做Pro*c/c++編程。
  

1 DB2的嵌入sql程序處理過程

  嵌入SQL程序處理,由一個源程序創建爲一個可執行文件(或庫)的過程。如下圖所示:
這裏寫圖片描述

  從上圖看出,首先對源文件做預編譯(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) $*.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章