PROC是Oracle數(shù)據(jù)庫提供的編程接口之一,其應(yīng)用十分的廣泛,本文通過一個具體的例子,介紹PROC編程的一些經(jīng)驗及應(yīng)注重的地方。 
  
  例子程序: 
  #include 
  #include 
  #include 
  #include 
  #include 
                                                                                              
  
  EXEC SQL INCLUDE sqlca; 
  /*RELEASE_CURSOR=YES 使PROC 在執(zhí)行完后釋放與嵌入SQL有關(guān)資源*/ 
  EXEC ORACLE OPTION (RELEASE_CURSOR = YES); 
  
  EXEC SQL BEGIN DECLARE SECTION; 
  varchar vc_user[20]; 
  long al_empno=0; 
  char ac_ename[11]=""; 
  char ac_hiredate[20]=""; 
  double af_sal=0; 
  
  EXEC SQL VAR ac_ename IS STRING(11); 
  EXEC SQL VAR ac_hiredate IS STRING(20); 
  
  EXEC SQL END DECLARE SECTION; 
  
  
  /*錯誤處理函數(shù)*/ 
  void sql_error(char *msg) 
  { 
  printf("/n%s,%ld,%s/n", msg,sqlca.sqlcode,(char *)sqlca.sqlerrm.sqlerrmc); 
  EXEC SQL ROLLBACK RELEASE; 
  exit(-1); 
  } 
  
  
  main() 
  { 
  EXEC SQL WHENEVER SQLERROR DO sql_error("ORACLE ERROR: "); 
  
  /*連接數(shù)據(jù)庫*/ 
  strcpy(vc_user.arr,"scott/tiger@DEMO"); 
  vc_user.len=16; 
  exec sql connect :vc_user; 
  
  EXEC SQL DECLARE cur_emp CURSOR FOR 
  SELECT EMPNO, ENAME,to_char(HIREDATE,'yyyy/mm/dd hh24:mi:ss'),SAL FROM EMP; 
  
  EXEC SQL OPEN cur_emp; 
  while(1) 
  { 
  al_empno=0; 
  strcpy(ac_ename,""); 
  strcpy(ac_hiredate,""); 
  af_sal=0; 
  EXEC SQL FETCH cur_emp INTO :al_empno, :ac_ename:ename_ind, :ac_hiredate:hiredate_ind, :af_sal:sal_ind; 
  if( sqlca.sqlcode == 1403) 
  { 
  break; 
  } 
  printf("empno=%ld,ename=%s,hiredate=%s,sal=%lf/n",al_empno,ac_ename,ac_hiredate,af_sal); 
  } 
  EXEC SQL CLOSE cur_emp; 
  EXEC SQL ROLLBACK WORK RELEASE; 
  } 
  
  
  
  1、宿主變量的聲明 
  在PROC中,在SQL語句中用到的變量稱為宿主變量。他們應(yīng)在EXEC SQL BEGIN DECLARE SECTION;與EXEC SQL EDN DECLARE SECTION; 
  之間聲明,如上面所示.在聲明宿主變量時應(yīng)注重以下幾點: 
  (1) 在數(shù)據(jù)庫表中定義為VARCHAR2,VARCHAR,CHAR的字段,在PROC中可聲明為CHAR,但長度應(yīng)為它們在表中定義的長度加1,因為PROC中 
  CHAR型變量用/0做結(jié)尾。 
  
  如:ENAME在表中的定義為ename varchar2(10),在PROC中可定義為: 
  EXEC SQL BEGIN DECLARE SECTION; 
  char ename[11]; 
  EXEC SQL END DECLARE SECTION; 
  常見錯誤說明: 
  假如插入的字符串長度大于10,如:EXEC SQL INSERT INTO EMP(ENAME) VALUES('12345678901');會出現(xiàn)以下錯誤: 
  error:ORA-01480: STR 賦值變量缺少空后綴。 
  
  假如定義為: 
  EXEC SQL BEGIN DECLARE SECTION; 
  char ename[15]; 
  EXEC SQL END DECLARE SECTION; 
  
  當插入的字符串長度大于10,小于15時,如:EXEC SQL INSERT INTO EMP(ENAME) VALUES('12345678901');會出現(xiàn)以下錯誤: 
  error:ORA-01401: 插入的值對于列過大。
                          
  當插入的字符串長度大于15,如:EXEC SQL INSERT INTO EMP(ENAME) VALUES('12345678901234');會出現(xiàn)以下錯誤: 
  error:ORA-01401:STR 賦值變量缺少空后綴。 
  
  (2) 從SQL語句中取字段的值到宿主變量中時,PROC不會自動給宿主變量去掉右空格。而是以在DECLARE SECTION 中定義的長度為準(與 表中定義的無關(guān))不足補右空格.假如不注重這一點,在PROC中進行字符串操作時(如比較相等)會出錯。如: 
  EXEC SQL BEGIN DECLARE SECTION; 
  char ename[10]; 
  EXEC SQL END DECLARE SECTION; 
  假如ENAME在表中的值為'abc',則取出的值為'abc '; 
  
  可用語句EXEC SQL VAR重定義CHAR型變量。這樣宿主變量會自動去掉右空格。如下: 
  EXEC SQL BEGIN DECLARE SECTION; 
  char ename[11]; 
  EXEC SQL VAR ac_ename IS STRING(11); 
  EXEC SQL END DECLARE SECTION; 
  假如ENAME在表中的值為'abc',則取出的值為'abc'; 
  
  (3) 對浮點型的變量,為保證精度,最好是聲明成DOUBLE型的.因為DOUBLE型的精度比FLOAT型高很多. 
  (4) 整型可聲明為LONG型(對較長的整型,而且所用的平臺支持的話,如在SUN平臺上,可聲明為LONG LONG型). 
  (5) DATE型的處理:DATE型一般聲明為CHAR(20)。 
  往表中插入DATE型數(shù)據(jù)時,一般用TO_DATE()函數(shù)進行類型轉(zhuǎn)換,取出值時一般用TO_CHAR()函數(shù)進行類型轉(zhuǎn)換. 
  EXEC SQL select to_char(hiredate,'yyyy/mm/dd hh24:mi:ss') into :ac_hire_date from EMP where empno=1234; 
  EXEC SQL insert into EMP(EMPNO,HIREDATE) values(123,to_date(:ac_hiredate,'yyyy/mm/dd hh24:mi:ss'); 
  
  
  2、宿主變量的作用范圍 
  假如宿主變量在所有的函數(shù)之外聲明,則他們是全局變量。在使用之前要注重把變量的值初始化,宿主變量也可以在某個函數(shù)的內(nèi)部定義。 這時他們是局部變量。一般都習慣把宿主變量聲明為全局變量。 
  
  3、數(shù)據(jù)庫的連接與斷開 
  數(shù)據(jù)庫的連接有以下兩種方法: 
  (1) 
  strcpy(vc_user.arr,"scott/tiger"); 
  vc_user.len=11; 
  exec sql connect :vc_user; 
  (2) 
  strcpy(user,"scott"); 
  strcpy(pass,"tiger"); 
  exec sql connect :user identified by :pass; 
  注重:在有些平臺上兩種都可以,在有些平臺上只能用第一種方法. 
  在PROC程序中,要記住用EXEC SQL ROLLBACK WORK RELEASE;斷開與數(shù)據(jù)庫的連接,并釋放相關(guān)的數(shù)據(jù)庫資源。 
  
  
  4、PROC中的NULL值的處理 
  假如某一字段取出的值是NULL,會報:sqlcode=-1405, sqlerr=ORA-01405: 讀取的列值為 NULL 
  并且相應(yīng)的宿主變量的值不會被改變,為執(zhí)行該SQL語句之前的值. 常用的處理NULL值的方法有: 
  (1)采用指示器變量,此時不會有-1405錯誤,當必須是所以為NULL的字段都有相應(yīng)的指示器變量,假如某一字段沒有指示器變量,但取出的值 
  為NULL值,則仍然會有-1405錯誤.當取出的值是NULL時,相應(yīng)的指示器變量變量為-1,可根據(jù)指示器變量的值做響應(yīng)的處理。 
  (2)假如字段較多,可取字段到一個結(jié)構(gòu)體中及與該結(jié)構(gòu)體對應(yīng)的指示器結(jié)構(gòu)體中.如上面的例子中可定義結(jié)構(gòu)體: 
  strUCt str_emp{ 
  long al_empno; 
  char ac_ename; 
  char ac_hiredate; 
  double af_sal; 
  }; 
  struct str_emp_ind{ 
  long al_empno; 
  char ac_ename; 
  char ac_hiredate; 
  double af_sal; 
  }; 
  
  struct str_emp str_emp; 
  strcut str_emp_ind str_emp_ind; 
  在取之前可用memset(&str_emp,0,sizeof(str_emp)).清空該結(jié)構(gòu)體,這樣假如是字符型的NULL,會為"",整型的NULL會為0, 
  浮點型的會為0.00。此時不會有-1405錯誤。 
  (3)也可采用NVL()函數(shù):舉例如下: 
  EXEC SQL DECLARE authors CURSOR FOR 
  SELECT EMPNO, NVL(ENAME,chr(0)),nvl(to_char(HIREDATE,'yyyy/mm/dd hh24:mi:ss'),chr(0)),NVL(SAL,0) FROM EMP; 
  這樣也不會有-1405錯誤不,當取出的值是NULL時,自動用NVL()中指定的值代替. 
  CHR(0)也可直接用''代替,如下: 
  SELECT EMPNO, NVL(ENAME,''),nvl(to_char(HIREDATE,'yyyy/mm/dd hh24:mi:ss'),''),NVL(SAL,0) FROM EMP; 
  
  
  5、PROC中的錯誤的處理 
  所有的SQL語句都有可能出錯.所以都要加以判定,但每個SQL語句后都加錯誤判定,太麻煩,可用一個函數(shù)如sql_error()來進行錯誤處理, 
  方法: 
  (1)定義ql_error()函數(shù)。
                          
  (2)在開頭加上EXEC SQL WHENEVER SQLERROR DO sql_error();這樣當發(fā)生sqlca.sqlcode <0 的錯誤時,程序自動轉(zhuǎn)到sql_error()中執(zhí)行. 注重:對sqlca.sqlcode >0的錯誤如 sqlca.sqlcode =1403 是不會轉(zhuǎn)到sql_error()中執(zhí)行的. 
  另外:在UNIX下,可以用OERR 來查找錯誤的描述。如: ora ORA -1405 查找錯誤號為-1405的描述. 
  
  
  6、PROC中調(diào)用存儲過程的方法 
  要把存儲過程放在EXEC SQL EXECUTE 和 END-EXEC;之間,如下所示: 
  其中:al_empno,ac_ename 為輸入?yún)?shù),l_return,l_errno,c_errtext 為輸出參數(shù)。 
  al_empno=8888; 
  strcpy(ac_ename,"ABCD"); 
  EXEC SQL EXECUTE 
  BEGIN 
  up_db_emp(:al_empno,:ac_ename,:l_return,:l_errno,:c_errtext); 
  END; 
  END-EXEC; 
  if (l_return != 0) 
  { 
  printf("調(diào)用UP_PB_EMP存儲過程出錯,errno=%ld,errtext=%s/n",l_errno,c_errtext); 
  } 
  
  7、PROC的命令行選項:PROC編譯器有很多的命令行選項,在命令行下直接不帶參數(shù)運行PROC,會列出所有的命令行選項來,并有說明。 
  (1)儲存過程:編譯儲存過程是要帶上用戶名及密碼 
  proc USERID=scott/tiger sqlcheck=SEMANTICS ireclen=512 iname=test.cpp 
  (2)PARSE=NONE 對非SQL代碼不進行語法分析,默認對非SQL