程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> SyBase數據庫 >> SyBase綜合文章 >> PRO*C程序移植為DBLIBRARY/C程序經驗談

PRO*C程序移植為DBLIBRARY/C程序經驗談

編輯:SyBase綜合文章
劉小余

  農行信用卡有關程序以前均為PRO*C程序,與Oracle數據庫相連。總行為與其它業務系統一致,將信用卡系統移植為Sybase數據庫下。但由此許多各行自行開發的信用卡輔助程序都面臨著移植的問題。我行所采用的海通天河電話銀行系統也因此不能使用。擱置達半年之久,對客戶也造成了極大不便,為此,我行對此系統進行了移植,也總結了一些經驗。現敘述如下,希望能對各位有所幫助。
  對PRO*C程序移植為DBLIBRARY/C可分以下幾個步驟:

一、 頭文件的修改

  由於PRO*C為在C程序中加入以EXEC SQL打頭的嵌入式SQL語言,而DBL IBRARY/C則為純C庫函數的形式提供。故需提供相應的頭文件。在PRO*C源程序中增加如下兩行:
  #include
  #include
  同時刪去原程序中以EXEC SQL INCLUDE打頭的語句,例如下格式的語句:
  EXEC SQL INCLUDE SQLCA.H

二、 變量定義的修改

  PRO*C中變量定義區以EXEC SQL BEGIN DECLARE打頭,以EXEC SQL END DECLARE SECTION結束,而DBL IBRARY/C有自定義的變量類型。一般與PRO*C中類型有如下對應:
  PRO*C DBLIBRARY/C
  VARCHAR one[20] DBCHAR one[20]
  float one DBFLT8 one
  double one DBFLT8 one
  char one[20] DBCHAR one[20]
  int one DBINT one
  刪去以變量定義區的開始,結束兩行,將其中變量按上述改為相應定義格式,同時增加兩個結構指針及一個返回變量:
  DBPROCESS *dbproc;
  LOGINREC *dblogin;
  RETCODE result_code;

三、 數據庫連接的修改

  PRO*C程序通過以下格式連接數據庫;
  strcpy(uid.str,″user″);
  strcpy(pwd.str,″passwd″);
  uid.len=strlen(uid.str);
  pwd.len=strlen(pwd.str);
  EXEC SQL CONNECT :uid IDENFITIED BY :pwd;
而DBLIBRARY/C連接方式如下:*
  dbinit();
  login=dblogin();
  DBSETLUSER(login,″user″);
  DBSETLPWD(login,″passwd″);
  DBSETLAPP(login,″application_name″);
  dbproc=dbopen(login,NULL);
  刪去原程序中PRO*C格式部分,增加DBLIBRARY/C部分。

四、 數據提取部分的修改

  PRO*C一般有兩種提取數據方式:
  1.直接用EXEC SQL SELECT語句返回數據至變量
  EXEC SQL SELECT curl,cur2 INTO :cur1,:cur2
   from table
   where 條件
  2.用游標返回一批數據,游標如下格式定義:
  EXEC SQL DECLAR cur sor_name CURSOR FOR
  select cur1,cur2 from table
   where條件
  使用時先打開它:
  EXEC SQL OPEN cursor_name
  然後利用循環返回這一批量數據:
  while(1)
  {
  EXEC SQL FETCH cursor_name into :m_curl,:m_cur2;
  /*其它處理*/
  …
  }
  最後關閉它:
  EXEC SQL CLOSE cursor_name:
  而DBLIBRARY/C的提取功能可一並處理上述兩種方式,

如下:
  dbcmd(dbproc,″select cur1,cur2 from table where條件″);
  dbsqlexec(dbproc);
  while((result_code=dbresults(dbproc))!=NO_MORE_RESU
LTS)
  {
   if(result_code= SUCCEED)
   {
   dbbind(dbproc,1,INTBIND,(DBINT)0,(BYTE*)&m_cur1);
  dbbind(dbproc,2,STRINGBIND,(DBINT)0,m_cur2);
  while(dbnextrow(dbproc)!=NO_MORE_ROWS)
   {
   /*對數據進行處理*/
   ……
   }
   }
  }
  其中dbbind()函數實現字段與變量一一對應的綁定功能,所涉及到的常用變量類型有如下對應關系:
  STRINGBIND DBCHAR
  INTBIND DBINT
  FLT8BIND DBFLT8
  需注意的是:如果不為字符型數據,則dbbind()函數中,須用(BYTE*)&的方式取其地址。

五、 其它數據處理的修改

  其它數據處理,如修改,刪除,插入等非查詢語句,
  在PRO*C中,一條語句EXEC SQL…即可,
  在DBL IBRARY/C中,也只需上一部分中的前兩行即可:
   dbcmd(dbproc,″update…″);
   dbsqlexec(dbproc);

六、 數據提交與回滾的處理

  PRO*C中,用如下語句:
  EXEC SQL COMMIT WORK 〖RELEASE〗;
或:
  EXEC SQL ROLLBACK WORK 〖RELEASE〗;
  此RELEASE參數的有無決定是否提交或回滾後即退出數據連接,而DBLIBRARY/C中,則如下處理:
  dbcmd(dbproc,″commit transcation″);
  dbsqlexec(dbproc);
或:
  dbcmd(dbproc,″rollback transcation″);
  dbsqlexec(dbpr


您正在看的Sybase教程是:PRO*C程序移植為DBLIBRARY/C程序經驗談。oc);

七、 增加退出語句

  PRO*C中用數據提交或回滾即可退出。
  而DBLIBRARY/C中須用專有退出函數:
   dbexit();

八、 對錯誤與未發現情況的處理

  PRO*C中通過EXEC SQL WHENEVER SQLERROR…與EXEC SQL WHENEVER NOT FOUND…實現。並在其後再定義之前一直有效。
  而DBLIBRARY/C中,則為增加兩個函數,並通過相應函數設為消息函數及錯誤函數。如下:
   int msg_handler();
   int err_handler();
   dbmsghandle(msg_handler);
   dberrhandle(err_handler);
  這兩個函數全局有效。msg_handler()及err_handler()函數可參考例子。另對具體數據操作過程,也可在dbsqlexec()調用後,再調用dbcount(dbproc),根據返回值(即所處理的數據行數)來確定成功與否。

九、 其它處理及編譯

  經過以上處理,可刪除所有以EXEC SQL起頭的PRO*C嵌入SQL語句及有關PRO*C特殊結構引用部分。例如:sqlca.sqlerrm.sqlerrmc等。檢查整個程序,相關的PRO*C嵌入SQL語句均改為DBLIBRARY/C語句後,即可進行編譯了。
  cc編譯命令行須加入如下參數:
  -I,-I$(SYBASE)/include$(Sybase)/lib/libsybdb.a -lnls_s-lm
  其中$(SYBASE)為Sybase系統的根目錄。

十、 補充及一點經驗

  1.對於可變的sql語句,可用dbfcmd()代替dbcmd();
  例:dbfcmd(dbproc,″select name from table where id=%d″,m_id);
  2.定義相應的環境變量SYBASE,DSQYERY及正確的interfaces文件後,可訪問遠程的Sybase數據庫。
  3.對較大的程序,如果數據分幾部分存取,可分別調用dbopen()函數,返回不同的DBPROCESS結構指針,但要注意,每個指針在使用完後,要用dbclose(dbproc)關閉。
  4.對於字符串變量,要注意其後的‘\0’結束符也需要占一位,定義時要比可能的最大長度大1。
  5.對於字符變量,最好定義其為DBCHAR型,長度為1。
  例:DBCHAR sample[1]。訪問時則用sample[0]。
  6.對於數據庫中為日期型的字段,可利用convert()將其轉為字符型輸出。
  例:
  dbcmd(dbproc,″select convert(char(10),open_date,112)from balance″);
  convert()的第三個參數決定日期轉換後的格式,常用取值如下:
    值      格式
     2     YY.MM.DD
     8    HH:MM:SS
    12    YYMMDD
    112     YYYYMMDD
  convert()還可對其它數據類型進行轉換,如欲了解詳情,可參閱有關書籍。
  7.PRO*C中的VARCHAR類型變量,實為一個如下的結構:
  typedef struct {
   char *str:
   int len;
   } VARCHAR;
  DBLIBRARY/C中不存在此變量類型,改為DBCHAR後,相應的訪問形式也須改為字符串型。
  8.dbmsghandle()函數可不調用,以避免不必要的信息破壞屏幕。
  9.下例也可進行sql優化,用如下sql語句代替原語句,即可不必進行循環,而直接采用第一行數據即可,由此也可見此類程序中sql優化的重要性。
  select name,age,balance from table order by balance desc
  為便於讀者理解,實際掌握,現舉例如下:
  現有一數據庫db,其上有一用戶名為user,口令為passwd。
  db中有一數據表table,其中數據如下:
  name age balance
  張三 26 1000.00
  李四 23 956.86
  王二 31 1200.00
  現有一程序,實現查出工資最高的人的資料。
  PRO*C程序如下(sample,pcc):
  #include
  #include
  main()
  {
  EXEC SQL BEGIN DECLARE SECTION;
   VARCHAR uid[20];
   VARCHAR pwd[20];
   VARCHAR m_name[20];
   int m_age
   float m_balance;
  EXEC SQL END DECLARE SECTION;
  EXEC SQL INCLUDE SQLCA.H;
  EXEC SQL WHENEVER SQLERROR goto quited;
   char t_name[20];
   int t_age;
   float t_balance=0.00;
   strcpy(uid.str,″user″);
   strcpy(pwd.str,″passwd″);
   uid.len=strlen(uid.str);
  pwd.len=strlen(uid.str);
   EXEC SQL CONNECT :uid IDENFITIED BY :pwd;
   EXEC SQL DECLARE CURSOR check
    select name,age,balance
   from table
   EXEC SQL WHENEVER NOT FOUND goto continued;
/*定義查到尾造成未發現情況時跳出循環*/
  EXEC SQL open check;
  while(1)
  {
   EXEC SQL FETCH check into :m_name,:m_age,:m_balance;
   if(m_balance>t_balance)
   {
   strcpy(t_name,m_name);
   t_age=m_ag


您正在看的Sybase教程是:PRO*C程序移植為DBLIBRARY/C程序經驗談。e;
   t_balance=m_balance;
   }
  }
continued:
  EXEC SQL CLOSE check;
  printf(″%s\t%d\t%.2f ″,t_name,str,t_age,t_balance);
  EXEC SQL COMMIT WORK RELASE;
  exit(0);
quited:
  printf(″%s″,sqlca.sqlerrm.sqlerrmc);
  EXEC SQL ROLLBACK RELASE;
  exit(-1);
}
  改為DBLIBRARY/C程序如下(sample.c):
  #include
  #include
  #include
  #include
  #define ERR_CH stderr
  int err_handler();
  int msg_handler();
  main()
  {
  DBPROCESS *dbproc;
  LOGINREC *login;;
  RETCODE result_code;
  DBCHAR m_name[20];
  DBINT m_age;
  DBFLT8 m_balance;
  char t_name [20];
  int t_age;
  float t_balance=0.00;
  if(dbinit()==FAIL)
   exit(-1);
  dberrhandle(err_handler);
  dbmsghandler(msg_handler);
  login=dblogin();
  DBSETLUSER(login,″user″);
  DBSETLPWD(login,″passwd″);
  DBSETLAPP(login,″sample″);
  dbproc=dbopen(login,NULL);
  dbcmd(dbproc,″select name,age,balance from table″);
  dbsqlexec(dbproc);
  while((result_code=dbresults(dbproc))!=NO_MORE_RESU
LTS)
  {
   if(result_code==SUCCEED)
   {
   dbbind(dbproc, 1, STRINGBIND, (DBINT)0, m_name);
   dbbind(dbproc,2,INTBIND,(DBINT)0,(BYTE*)&m_age);
   dbbind(dbproc,3,FLT8BIND,(DBINT)0,(BYTE*)&m_balance);
   while(dbnextrow(dbproc)!=NO_MORE_ROWS)
   {
   if(m_balance>t_balance)
   {
   strcpy(t_name,m_name);
   t_age=m_age;
   t_balance=m_balance;
   }
   }
   }
   printf(″%s\t%d\%.2f″,t_name,t_age,t_balance);
   dbexit();
   exit(0);
  }
  int err_handler(dbproc,severity,dberr,oserr,dberrstr,

oserrstr)
  DBPROCESS dbproc;
  int severity;
  int dberr;
  int oserr;
  char *dberrstr;
  char *oserrstr;
  {
   if ((dbproc==NULL)‖(DBDEAD(dbproc)))
   return(INT_EXIT);
   else
   {
   fprintf (ERR_CH,″DB-Library error;\n\t%s\n″,dberrstr);
   if(oserr!=DBNOERR)
   fprintf (ERR_CH,″Operating-system error:\n\t%s\n″,oserrstr);
   return(INT_CANCEL);
   }
}   

  int msg_handler(dbproc,msgno,msgstate,severity,msgtext,
   srvname,procname,line)
  DBPROCESS * dbproc;
  DBINT msgno;
  int msgstate;
  int severity;
  char *msgtext;
  char *srvname;
  char *procname;
  DBUSMALLINT line
{
  fprintf(ERR_CH,″Msg %ld,Level %d,State %d\n″,
msgno,severity,msgstate);
  if(strlen(srvname)>0)
   fprintf (ERR_CH,″Server'%s',″,srvname);
  if (strlen(procname)>0)
   fprintf (ERR_CH,″Procedure'%s,″,procname);
  if(line>0)
   fprintf(ERR_CH,″Line %d″,line);
  fprintf (ERR_CH,″\n\t%s\n″,msgtext);
  return(0);
}
  如$(SYBASE)=/u/Sybase,編譯命令行如下:
  cc -I.-I/u/sybase/include sample.c /u/Sybase/lib/libsybdb.a-lnsl_s-lm-o sample
  PRO*C和DBL IBRARY/C是兩種典型的數據庫應用程序設計接口:一為嵌入式SQL方法,一為提供純C函數方法。所涉及到的知識是比較龐雜的,作者也僅是略窺門徑。希望本文若能對有興趣的讀者起到引門入徑之作用,則吾願足矣。

作者單位:劉小余(中國農業銀行新疆自治區塔城地區分行信息電腦中心 新疆 塔城 834700)

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved