介绍Pro*c编程的经验
生活随笔
收集整理的這篇文章主要介紹了
介绍Pro*c编程的经验
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
聲明:本文章轉(zhuǎn)載http://blog.csdn.net/luolunz/article/details/7490711,只為備忘筆記使用,如有侵權(quán)通知我
PROC是ORACLE數(shù)據(jù)庫(kù)提供的編程接口之一,其應(yīng)用十分的廣泛,本文通過(guò)一個(gè)具體的例子,介紹PROC編程的一些經(jīng)驗(yàn)及應(yīng)注意的地方。
例子程序:#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sqlda.h>
#include <sqlcpr.h>
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;
/*錯(cuò)誤處理函數(shù)*/
void sql_error(char *msg)
{
printf(" %s,%ld,%s ", 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ù)庫(kù)*/
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 ",al_empno,ac_ename,ac_hiredate,af_sal);????
}????
EXEC SQL CLOSE cur_emp;
EXEC SQL ROLLBACK WORK RELEASE;
} 1、宿主變量的聲明?
在PROC中,在SQL語(yǔ)句中用到的變量稱為宿主變量。他們應(yīng)在EXEC SQL BEGIN DECLARE SECTION;與EXEC SQL EDN DECLARE SECTION;?
之間聲明,如上面所示.在聲明宿主變量時(shí)應(yīng)注意以下幾點(diǎn):?
(1) 在數(shù)據(jù)庫(kù)表中定義為VARCHAR2,VARCHAR,CHAR的字段,在PROC中可聲明為CHAR,但長(zhǎng)度應(yīng)為它們?cè)诒碇卸x的長(zhǎng)度加1,因?yàn)镻ROC中?
CHAR型變量用做結(jié)尾。?
?
如:ENAME在表中的定義為ename varchar2(10),在PROC中可定義為:?
EXEC SQL BEGIN DECLARE SECTION;?
char ename[11];?
EXEC SQL END DECLARE SECTION;?
常見(jiàn)錯(cuò)誤說(shuō)明:?
如果插入的字符串長(zhǎng)度大于10,如:EXEC SQL INSERT INTO EMP(ENAME) VALUES('12345678901');會(huì)出現(xiàn)以下錯(cuò)誤:?
error:ORA-01480: STR 賦值變量缺少空后綴。?
?
如果定義為:?
EXEC SQL BEGIN DECLARE SECTION;?
char ename[15];?
EXEC SQL END DECLARE SECTION;?
?
當(dāng)插入的字符串長(zhǎng)度大于10,小于15時(shí),如:EXEC SQL INSERT INTO EMP(ENAME) VALUES('12345678901');會(huì)出現(xiàn)以下錯(cuò)誤:?
error:ORA-01401: 插入的值對(duì)于列過(guò)大。?
當(dāng)插入的字符串長(zhǎng)度大于15,如:EXEC SQL INSERT INTO EMP(ENAME) VALUES('12345678901234');會(huì)出現(xiàn)以下錯(cuò)誤:?
error:ORA-01401:STR 賦值變量缺少空后綴。?
?
(2) 從SQL語(yǔ)句中取字段的值到宿主變量中時(shí),PROC不會(huì)自動(dòng)給宿主變量去掉右空格。而是以在DECLARE SECTION 中定義的長(zhǎng)度為準(zhǔn)(與 表中定義的無(wú)關(guān))不足補(bǔ)右空格.如果不注意這一點(diǎn),在PROC中進(jìn)行字符串操作時(shí)(如比較相等)會(huì)出錯(cuò)。如:?
EXEC SQL BEGIN DECLARE SECTION;?
char ename[10];?
EXEC SQL END DECLARE SECTION;??
如果ENAME在表中的值為'abc',則取出的值為'abc ';?
?
可用語(yǔ)句EXEC SQL VAR重定義CHAR型變量。這樣宿主變量會(huì)自動(dòng)去掉右空格。如下:??
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) 對(duì)浮點(diǎn)型的變量,為保證精度,最好是聲明成DOUBLE型的.因?yàn)镈OUBLE型的精度比FLOAT型高很多.?
(4) 整型可聲明為L(zhǎng)ONG型(對(duì)較長(zhǎng)的整型,而且所用的平臺(tái)支持的話,如在SUN平臺(tái)上,可聲明為L(zhǎng)ONG LONG型).?
(5) DATE型的處理:DATE型一般聲明為CHAR(20)。?
往表中插入DATE型數(shù)據(jù)時(shí),一般用TO_DATE()函數(shù)進(jìn)行類型轉(zhuǎn)換,取出值時(shí)一般用TO_CHAR()函數(shù)進(jìn)行類型轉(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ù)之外聲明,則他們是全局變量。在使用之前要注意把變量的值初始化,宿主變量也可以在某個(gè)函數(shù)的內(nèi)部定義。 這時(shí)他們是局部變量。一般都習(xí)慣把宿主變量聲明為全局變量。?
?
3、數(shù)據(jù)庫(kù)的連接與斷開(kāi)?
數(shù)據(jù)庫(kù)的連接有以下兩種方法:?
(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;?
注意:在有些平臺(tái)上兩種都可以,在有些平臺(tái)上只能用第一種方法.?
在PROC程序中,要記住用EXEC SQL ROLLBACK WORK RELEASE;斷開(kāi)與數(shù)據(jù)庫(kù)的連接,并釋放相關(guān)的數(shù)據(jù)庫(kù)資源。?
?
?
4、PROC中的NULL值的處理?
如果某一字段取出的值是NULL,會(huì)報(bào):sqlcode=-1405, sqlerr=ORA-01405: 讀取的列值為 NULL?
并且相應(yīng)的宿主變量的值不會(huì)被改變,為執(zhí)行該SQL語(yǔ)句之前的值. 常用的處理NULL值的方法有:?
(1)采用指示器變量,此時(shí)不會(huì)有-1405錯(cuò)誤,當(dāng)必須是所以為NULL的字段都有相應(yīng)的指示器變量,如果某一字段沒(méi)有指示器變量,但取出的值?
為NULL值,則仍然會(huì)有-1405錯(cuò)誤.當(dāng)取出的值是NULL時(shí),相應(yīng)的指示器變量變量為-1,可根據(jù)指示器變量的值做響應(yīng)的處理。?
(2)如果字段較多,可取字段到一個(gè)結(jié)構(gòu)體中及與該結(jié)構(gòu)體對(duì)應(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,會(huì)為"",整型的NULL會(huì)為0,?
浮點(diǎn)型的會(huì)為0.00。此時(shí)不會(huì)有-1405錯(cuò)誤。?
(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;?
這樣也不會(huì)有-1405錯(cuò)誤不,當(dāng)取出的值是NULL時(shí),自動(dòng)用NVL()中指定的值代替.?
CHR(0)也可直接用''代替,如下:?
SELECT EMPNO, NVL(ENAME,''),nvl(to_char(HIREDATE,'yyyy/mm/dd hh24:mi:ss'),''),NVL(SAL,0) FROM EMP;?
?
?
5、PROC中的錯(cuò)誤的處理?
所有的SQL語(yǔ)句都有可能出錯(cuò).所以都要加以判斷,但每個(gè)SQL語(yǔ)句后都加錯(cuò)誤判斷,太麻煩,可用一個(gè)函數(shù)如sql_error()來(lái)進(jìn)行錯(cuò)誤處理,?
方法:?
(1)定義ql_error()函數(shù)。?
(2)在開(kāi)頭加上EXEC SQL WHENEVER SQLERROR DO sql_error();這樣當(dāng)發(fā)生sqlca.sqlcode <0 的錯(cuò)誤時(shí),程序自動(dòng)轉(zhuǎn)到sql_error()中執(zhí)行. 注意:對(duì)sqlca.sqlcode >0的錯(cuò)誤如 sqlca.sqlcode =1403 是不會(huì)轉(zhuǎn)到sql_error()中執(zhí)行的.?
另外:在UNIX下,可以用OERR 來(lái)查找錯(cuò)誤的描述。如: ora ORA -1405 查找錯(cuò)誤號(hào)為-1405的描述.?
?
?
6、PROC中調(diào)用存儲(chǔ)過(guò)程的方法?
要把存儲(chǔ)過(guò)程放在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存儲(chǔ)過(guò)程出錯(cuò),errno=%ld,errtext=%s ",l_errno,c_errtext);?
}?
?
7、PROC的命令行選項(xiàng):PROC編譯器有很多的命令行選項(xiàng),在命令行下直接不帶參數(shù)運(yùn)行PROC,會(huì)列出所有的命令行選項(xiàng)來(lái),并有說(shuō)明。?
(1)儲(chǔ)存過(guò)程:編譯儲(chǔ)存過(guò)程是要帶上用戶名及密碼?
proc USERID=scott/tiger sqlcheck=SEMANTICS ireclen=512 iname=test.cpp?
(2)PARSE=NONE 對(duì)非SQL代碼不進(jìn)行語(yǔ)法分析,默認(rèn)對(duì)非SQL代碼也進(jìn)行語(yǔ)法分析.?
在RED HAD6.3上的ORACLE8.1.5中用PROC時(shí),會(huì)提示:/USR/INCLUDE/STDIO.H 及其他的.H文件中有錯(cuò). 可把PARSE=NONE加上,就好了.?
?
?
8、注意加上:EXEC ORACLE OPTION (RELEASE_CURSOR = YES);?
RELEASE_CURSOR=YES 使PROC 在執(zhí)行完后釋放與嵌入SQL有關(guān)資源,保證在該P(yáng)ROC程序執(zhí)行完后,ORACLE不會(huì)鎖住數(shù)據(jù)庫(kù)資源,如鎖表等。?
如果在PROC中用到ORACA,還要在程序頭加上:?
EXEC ORACLE OPTION (ORACA=YES);?
?
9、PROC中的類型轉(zhuǎn)換?
一、在C語(yǔ)言中:?
(1)字符型到整型可用ATOI() ATOL(),SSCANF()?
(2)整型,浮點(diǎn)型到字符型,可用SPRINTF()?
(3)字符型到浮點(diǎn)型用ATOF()不行,最好用SSCANF(),舉例如下:?EXEC SQL BEGIN DECLARE SECTION;
double d_demo;
float f_demo;
char ac_text[20]="222";
EXEC SQL END DECLARE SECTION;????
(1)sscanf(ac_text, "%f", &d_demo);
printf("ac_text=%s,d_demo=%f ",ac_text,d_demo);
(2)sscanf(ac_text, "%lf", &d_demo);
printf("ac_text=%s,d_demo=%f ",ac_text,d_demo);
(3)sscanf(ac_text, "%f", &d_demo);
printf("ac_text=%s,d_demo=%lf ",ac_text,d_demo);
(4)sscanf(ac_text, "%lf", &d_demo);
printf("ac_text=%s,d_demo=%lf ",ac_text,d_demo);
printf("******************* ");
(5)sscanf(ac_text, "%f", &f_demo);
printf("ac_text=%s,f_demo=%f ",ac_text,f_demo);
(6)sscanf(ac_text, "%lf", &f_demo);
printf("ac_text=%s,f_demo=%f ",ac_text,f_demo);
(7)sscanf(ac_text, "%f", &f_demo);
printf("ac_text=%s,f_demo=%lf ",ac_text,f_demo);
(8)sscanf(ac_text, "%lf", &f_demo);
printf("ac_text=%s,f_demo=%lf ",ac_text,f_demo);
輸出的結(jié)果:????
ac_text=222.00,d_demo=0.000000????
ac_text=222.00,d_demo=222.000000????
ac_text=222.00,d_demo=222.000032????
ac_text=222.00,d_demo=222.000000????
*******************????
ac_text=222.00,f_demo=222.000000????
ac_text=222.00,f_demo=0.000000????
ac_text=222.00,f_demo=222.000000????
ac_text=222.00,f_demo=0.000000????
d_demo=atof(ac_text);
printf("ac_text=%s,atof(ac_text)=%f ",ac_text,d_demo);
d_demo=atof(ac_text);
printf("ac_text=%s,atof(ac_text)=%lf ",ac_text,d_demo);
f_demo=atof(ac_text);
printf("ac_text=%s,atof(ac_text)=%f ",ac_text,f_demo);
f_demo=atof(ac_text);
printf("ac_text=%s,atof(ac_text)=%lf ",ac_text,f_demo);
輸出的結(jié)果:????
ac_text=222.00,atof(ac_text)=1243288.000000
ac_text=222.00,atof(ac_text)=1243288.000000
ac_text=222.00,atof(ac_text)=1243288.000000
ac_text=222.00,atof(ac_text)=1243288.000000
從上面的結(jié)果可見(jiàn):?
DOUBLE型應(yīng)采用sscanf(ac_app_capcity, "%lf", &d_app); 打印用"%lf","%f" 都可以. (2),(4)正確?
FLOAT型應(yīng)采用sscanf(ac_app_capcity, "%f", &d_app); 打印用"%lf","%f" 都可以. (5),(7)正確?
采用ATOF()轉(zhuǎn)換的結(jié)果都是錯(cuò)的,所以不要用它。?
?
二、寫(xiě)表或從表中取數(shù)據(jù)時(shí):?
(1)字符型與整型之間可不用轉(zhuǎn)換,采用默認(rèn)方式。?
(2)字符型與浮點(diǎn)型之間可不用轉(zhuǎn)換,采用默認(rèn)方式。?
(3)日期型與字符型之間可用TO_CHAR(),TO_DATE()。?
?
?
10、PROC中的4種動(dòng)態(tài)SQL簡(jiǎn)介?
(1)動(dòng)態(tài)SQL1: 不能是查詢(SELECT)語(yǔ)句,并且沒(méi)有宿主變量.??
用法:拼一串動(dòng)態(tài)SQL語(yǔ)句,并用EXECUTE IMMEDIATE執(zhí)行,如:?
EXEC SQL EXECUTE IMMEDIATE "CREATE TABLE dyn1 (col1 VARCHAR2(4))";?
?
(2)動(dòng)態(tài)SQL2: 不能是查詢(SELECT)語(yǔ)句,并且輸入的宿主變量數(shù)目是知道的,?
用法:拼一串動(dòng)態(tài)SQL語(yǔ)句,用PREPARE,EXECUTE語(yǔ)句執(zhí)行.?
strcpy(c_sql, "DELETE FROM EMP WHERE EMPNO = :?");??
EXEC SQL PREPARE sql_stmt FROM :c_sql;?
EXEC SQL EXECUTE sql_stmt USING :emp_number;??
?
(3)動(dòng)態(tài)SQL3: 用于創(chuàng)建動(dòng)態(tài)查詢, 并且要查詢的字段及輸入的宿主變量數(shù)目是知道的?
用法: 拼一串動(dòng)態(tài)SQL語(yǔ)句,用PREPARE分析該語(yǔ)句,并要定義一個(gè)CURSOR進(jìn)行取值?
如:如要查詢的數(shù)據(jù)按一年12月放到12張表中。表名為user_fee_1mon, user_fee_2mon,....可采用動(dòng)態(tài)SQL3來(lái)進(jìn)行查詢?strcpy(c_sql,"select c_user_id,c_user_name,to_char(t_date,'yyyy/mm/dd hh:mi:ss'),n_fee ");
strcat(c_sql,"from USER_FEE_");
strcat(c_sql,ac_mon);
strcat(c_sql," where c_user_id = :v1");
EXEC SQL PREPARE s FROM :c_sql;
EXEC SQL DECLARE cur_user_fee CURSOR FOR s;
EXEC SQL OPEN cur_user_fee USING :ac_user_id;
while(1)
{????
EXEC SQL FETCH cur_user_fee into :c_user_id,:c_user_name,:c_date,:n_fee);
if (sqlca.sqlcode < 0)
{????
/*FETCH CURSOR失敗*/????
printf("fetch cursor cur_user_fee fail,sqlcode=%ld,sqlserr=%s",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
}
if( sqlca.sqlcode == SQLNOTFOUND)
{
break;
}
}
EXEC SQL CLOSE cur_user_fee;????(4)動(dòng)態(tài)SQL4:要處理的字段及輸入的宿主變量數(shù)目和主變量的類型事先是不知道的,如:?
INSERT INTO EMP (<unknown>) VALUES (<unknown>)?
是最復(fù)雜的動(dòng)態(tài)SQL,很少用,在此不做介紹。?
?
?
11、SQLCA:SQL是ORACLE的一個(gè)結(jié)構(gòu)體,它的域用于最近的一條SQL語(yǔ)句執(zhí)行后的一些信息,如錯(cuò)誤號(hào),錯(cuò)誤描述,警告,狀態(tài)等。常用的?
域介紹如下:?
SQLCA.sqlcode:錯(cuò)誤號(hào),=0正確,=1403沒(méi)取到數(shù)據(jù)?
SQLCA.sqlserrm.sqlerrmc:錯(cuò)誤描述?
SQLCA.sqlerrd[3]:最近的一條SQL語(yǔ)句所處理的行數(shù),如果該語(yǔ)句處理失敗,則它的值是不定的,如果錯(cuò)誤在一個(gè)CURSOR操作中發(fā)生,則?
它的值指已成功處理的行數(shù).在DELETE,UPDATE中,它不包含因外鍵約束而刪除,更新的那些行,??
DELETE FROM EMP WHERE DEPT='SALE';?
在表EMP中刪除20行,但如果表EMP與表ADDRESS有外鍵約束,導(dǎo)致表ADDRESS也被刪除20行,則SQLCA.sqlerrd[3]=20,而不是40。------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Pro*C介紹-內(nèi)嵌SQL?
[ Translate by Z.Jingwei. Document address:http://www-db.stanford.edu/~ullman/fcdb/oracle/or-proc.html?]?
Pro*C介紹
內(nèi)嵌SQL--------------------------------------------------------------------------------概要?
Pro*C語(yǔ)法?
SQL?
預(yù)處理指令?
語(yǔ)句標(biāo)號(hào)?
宿主變量?
基礎(chǔ)?
指針?
結(jié)構(gòu)?
數(shù)組?
指示器變量?
數(shù)據(jù)類型同等化?
動(dòng)態(tài)SQL?
事務(wù)?
錯(cuò)誤處理?
SQLCA?
WHENEVER語(yǔ)句?
Demo程序?
C++用戶?
List of Embedded SQL Statements Supported by Pro*C--------------------------------------------------------------------------------概要
內(nèi)嵌SQL是結(jié)合高級(jí)語(yǔ)言如C/C++的計(jì)算能力和SQL數(shù)據(jù)庫(kù)處理能力的一種方法。它允許你在程序中執(zhí)行任意的SQL語(yǔ)句。Oracle的嵌入SQL環(huán)境稱為Pro*C。Pro*C程序分兩步編譯。首先,Pro*C的預(yù)編譯器識(shí)別出嵌入在程序中的SQL語(yǔ)句,并將這些語(yǔ)句轉(zhuǎn)換為對(duì)SQL運(yùn)行時(shí)庫(kù)(SQL runtime library)中功能(functions)的適當(dāng)調(diào)用。輸出是純C/C++代碼和未被處理的純C/C++代碼。然后,用常規(guī)C/C++編譯器編譯代碼并生成可執(zhí)行程序。更詳細(xì)的內(nèi)容請(qǐng)參考Demo程序。Demo程序。
--------------------------------------------------------------------------------Pro*C語(yǔ)法--------------------------------------------------------------------------------SQL
所有SQL語(yǔ)句都要以EXEC SQL開(kāi)始,并用分號(hào)";"結(jié)束。SQL語(yǔ)句可以放置在C/C++塊中的任何地方,但可執(zhí)行的(SQL)語(yǔ)句應(yīng)該在聲明語(yǔ)句后面。例:{
??? int a;
??? /* ... */
??? EXEC SQL SELECT salary INTO :a
???????????? FROM Employee
???????????? WHERE SSN=876543210;
??? /* ... */
??? printf("The salary is %d ", a);
??? /* ... */
}
--------------------------------------------------------------------------------預(yù)處理指令
能夠在Pro*C中正常工作的C/C++預(yù)處理指令是#include和#if。Pro*C不能識(shí)別#define。下面的代碼是錯(cuò)誤的:#define THE_SSN 876543210
/* ... */
EXEC SQL SELECT salary INTO :a
???????? FROM Employee
???????? WHERE SSN = THE_SSN;/* INVALID */--------------------------------------------------------------------------------語(yǔ)句標(biāo)號(hào)
可以在SQL中跳轉(zhuǎn)到C/C++標(biāo)記EXEC SQL WHENEVER SQLERROR GOTO error_in_SQL;
??? /* ... */
error_in_SQL:
??? /* do error handling */
我們會(huì)在后面的錯(cuò)誤處理一節(jié)中講到有關(guān)WHENEVER的含意。錯(cuò)誤處理一節(jié)中講到有關(guān)WHENEVER的含意。
--------------------------------------------------------------------------------宿主變量--------------------------------------------------------------------------------基礎(chǔ)
宿主變量是連接宿主程序與數(shù)據(jù)庫(kù)的關(guān)鍵。宿主變量表達(dá)式必須視為(resolve to)左值(能被賦值)。你可以像聲明普通C變量一樣,按著C的語(yǔ)法規(guī)則聲明宿主變量。宿主變量的聲明可以放置在任何C變量聲明可以放置的地方。(C++用戶需要使用"DECLARE SECTION";參考C++ Users) Oracle可以使用的C數(shù)據(jù)類型包括:C++ Users) Oracle可以使用的C數(shù)據(jù)類型包括:
char?
char[n]?
int?
short?
long?
float?
double?
VARCHAR[n] - 它是能被Pro*C的預(yù)編譯器識(shí)別的預(yù)處理類型(psuedo-type)。它用來(lái) 表示由空白填充(blank-padded,譯注:'')的變長(zhǎng)字符串。Pro*C預(yù)編譯器會(huì)把它轉(zhuǎn)換為有一個(gè)2字節(jié)(byte)長(zhǎng)的域和一個(gè)n字(byte)長(zhǎng)的字符數(shù)組的結(jié)構(gòu)體。?
你不能指定寄存器存儲(chǔ)類型(譯注:指針)為宿主變量。可以在SQL表達(dá)式中使用冒號(hào)":"做前綴來(lái)引用一個(gè)宿主變量,但不能在C表達(dá)式中用分號(hào)做前綴。當(dāng)使用字符串作為宿主變量時(shí),必須省略引用;Pro*C明白你正指定一個(gè)基于宿主變量聲明類型的字符串(譯注:這句的意思是,當(dāng)定義一個(gè)字符串做為宿主變量時(shí)char *str="string",在嵌入SQL中使用時(shí),要省略"*"而不是*str)。不能將C函數(shù)調(diào)用和多數(shù)的指針計(jì)算表達(dá)式作為宿主變量使用,即使它們確實(shí)被解釋為左值。下面的代碼同時(shí)說(shuō)明了合法和不合法的宿主變量的引用:int deptnos[3] = { 000, 111, 222 };
int get_deptno() { return deptnos[2]; }
int *get_deptnoptr() { return &(deptnos[2]); }
int main()?
{
??? int x; char *y; int z;
??? /* ... */
??? EXEC SQL INSERT INTO emp(empno, ename, deptno)
??????? VALUES(:x, :y, :z); /* LEGAL */
??? EXEC SQL INSERT INTO emp(empno, ename, deptno)
??????? VALUES(:x + 1,? /* LEGAL: the reference is to x */
?????????????? 'Big Shot',? /* LEGAL: but not really a host var */
?????????????? :deptnos[2]);/* LEGAL: array element is fine */
??? EXEC SQL INSERT INTO emp(empno, ename, deptno)
??????? VALUES(:x, :y,
?????????????? :(*(deptnos+2)));/* ILLEGAL: although it has anlvalue */
??? EXEC SQL INSERT INTO emp(empno, ename, deptno)
??????? VALUES(:x, :y,
?????????????? :get_deptno());? /* ILLEGAL: no function calls */
??? EXEC SQL INSERT INTO emp(empno, ename, deptno)
??????? VALUES(:x, :y,
?????????????? :(*get_depnoptr())); /* ILLEGAL: although it has an lvalue */
??? /* ... */
}
--------------------------------------------------------------------------------指針
可以在SQL表達(dá)式中使用普通C語(yǔ)法聲明的指針。通常使用一個(gè)冒號(hào)做前綴:int*x;
/*...*/
EXEC SQL SELECT xyz INTO :x FROM ...;
這個(gè)SELECT語(yǔ)句的結(jié)果會(huì)寫(xiě)入*x,而不是x。
--------------------------------------------------------------------------------結(jié)構(gòu)
結(jié)構(gòu)同樣可以作為宿主變量使用,如下面例子:typedef struct {
??? char name[21];/* one greater than column length; for '' */
??? int SSN;
} Emp;
/* ... */
Emp bigshot;
/* ... */
EXEC SQL INSERT INTO emp (ename, eSSN)
??? VALUES (:bigshot);
--------------------------------------------------------------------------------數(shù)組
像下面這樣使用宿主數(shù)組:int emp_number[50];
char name[50][11];
/* ... */
EXEC SQL INSERT INTO emp(emp_number, name)
??? VALUES (:emp_number, :emp_name);
這樣會(huì)一次插入所有的50個(gè)元素(tuples)。數(shù)組只能是一維數(shù)組。例子中的char name[50][11]可能看起來(lái)與這個(gè)規(guī)則矛盾,然而,Pro*C實(shí)際上把name視為一維字符串?dāng)?shù)組而不是二維字符數(shù)組。也可以使用結(jié)構(gòu)數(shù)組。當(dāng)使用數(shù)組存放查詢結(jié)果時(shí),如果宿主數(shù)組的大小(n)小于實(shí)際查詢后返回的結(jié)果數(shù)量時(shí),那么只有(查詢出來(lái)的)前n個(gè)結(jié)果被填入宿主數(shù)組。
--------------------------------------------------------------------------------指示器變量
指示器實(shí)際上是附在宿主變量后的"NULL標(biāo)記"。每一個(gè)宿主變量都可以選擇性的關(guān)聯(lián)到一個(gè)指示器變量上。指示器變量的類型必須為2字節(jié)×××值(short類型),而且必須緊隨在宿主變量后且用冒號(hào)做為前綴。你也可以使用關(guān)鍵字INDICATOR放在宿主變量和指示器變量之間。例如:short indicator_var;
EXEC SQL SELECT xyz INTO :host_var:indicator_var
??? FROM ...;
/* ... */
EXEC SQL INSERT INTO R
??? VALUES(:host_var INDICATOR :indicator_var, ...);
在SELECT的INTO子句中使用的指示器變量可以用來(lái)檢查返回給宿主變量的值為空(NULL)或被截?cái)嗟牡那闆r。Oracle能夠賦給指示器變量的值具有下面各項(xiàng)意義:-1 字段(譯注:原文為column,意為該字段的列)值為NULL,宿主變量的值不確定。?
0 Oracle把完整的字值賦給了宿主變量。?
>0 Oracle把被截?cái)嗟淖侄沃蒂x給了宿主變量。指示器變量返回的×××值是字段的原始長(zhǎng)度。?
-2 Oracle把被截?cái)嗟淖侄沃蒂x給了宿主變量,但原字段值是不確定的。(譯注:這種情況可能是數(shù)值型的值被切斷后不能確定原始值)你也可以在INSERT或UPDATE的VALUES和SET子句中使用指示器變量指明用于輸入的宿主變量為NULL值。你的程序可以賦給指示器變量的值具有如下各項(xiàng)意義:-1 Oracle會(huì)忽略宿主變量的值并給字段賦一個(gè)NULL值。?
>=0 Oracle會(huì)將宿主變量的值賦給字段。
--------------------------------------------------------------------------------數(shù)據(jù)類型同等化
Oracle認(rèn)識(shí)兩種數(shù)據(jù)類型:內(nèi)部類型和外部類型。內(nèi)部數(shù)據(jù)類型指示Oracle在數(shù)據(jù)庫(kù)表中如何存儲(chǔ)字段。外部數(shù)據(jù)類型指示如何格式化存儲(chǔ)在宿主變量中用于輸入或輸出的值。在預(yù)編譯期,每一個(gè)宿主變量會(huì)被賦予一個(gè)默認(rèn)的Oracle外部數(shù)據(jù)類型。數(shù)據(jù)類型同等化允許你重載默認(rèn)的同等化,并允許你控制Oracle輸入數(shù)據(jù)的解釋和輸出數(shù)據(jù)的格式化。同等化通過(guò)使用VAR表達(dá)式實(shí)現(xiàn)基于從變量到變量的轉(zhuǎn)換。語(yǔ)法是:EXEC SQL VAR? IS? [ () ];
舉例來(lái)說(shuō), 假設(shè)你想從emp表中查詢雇員名子,然后傳給一個(gè)需要C類型(以''結(jié)尾的)字符串的程序,你不需要顯式的用''來(lái)結(jié)束這個(gè)名子。如下面所示,簡(jiǎn)單地將宿主變量同等化為外部數(shù)據(jù)類型STRING:char emp_name[21];
EXEC SQL VAR emp_name IS STRING(21);
emp表中ename字段的長(zhǎng)是20字符(character),因此,需要分配21字符(character)以適應(yīng)''結(jié)束符。Oracle的外部數(shù)據(jù)類型STRING是為C類型字符串特別設(shè)計(jì)的接口。當(dāng)把ename字段值傳給emp_name時(shí),Oracle會(huì)自動(dòng)用' '結(jié)尾。也可以使用TYPE語(yǔ)句將用戶自定義數(shù)據(jù)類型同等化為Oracle外部數(shù)據(jù)類型。語(yǔ)法是:EXEC SQL TYPE? IS? [ () ] [REFERENCE];
可以聲明一個(gè)用戶自定義類型的指針,顯式的如指向標(biāo)量或結(jié)構(gòu)的指針,或隱式的如數(shù)組,然后在TYPE表達(dá)式中使用這個(gè)類型。這種情況下,你需要在表達(dá)式后使用REFERENCE子句,如下所示:typedef unsigned char *my_raw;
EXEC SQL TYPE my_raw IS VARRAW(4000) REFERENCE;
my_raw buffer;
/* ... */
buffer = malloc(4004);
這里,我們分配了比源類型長(zhǎng)(4000)更多的內(nèi)存,這是因?yàn)轭A(yù)編譯器要返回長(zhǎng)度,而且可能需要填充適當(dāng)?shù)拈L(zhǎng)度以滿足系統(tǒng)的對(duì)齊要求。
--------------------------------------------------------------------------------動(dòng)態(tài)SQL
嵌入SQL能夠滿足一個(gè)固定的應(yīng)用,但有時(shí)動(dòng)態(tài)產(chǎn)生完整的SQL語(yǔ)句也是很重要的。對(duì)于動(dòng)態(tài)SQL,語(yǔ)句存儲(chǔ)在字符串變量中,PREPARE把字符串轉(zhuǎn)換為SQL語(yǔ)句,然后用EXECUTE執(zhí)行這個(gè)語(yǔ)句。考慮下面的例子:char *s = "INSERT INTO emp VALUES(1234, 'jon', 3)";
EXEC SQL PREPARE q FROM :s;
EXEC SQL EXECUTE q;
PREPARE和EXECUTE可放到一個(gè)語(yǔ)句中,像這樣:char *s = "INSERT INTO emp VALUES(1234, 'jon', 3)";
EXEC SQL EXECUTE IMMEDIATE :s;
--------------------------------------------------------------------------------事務(wù)
Oracle Pro*C支持標(biāo)準(zhǔn)SQL定義的事務(wù)。一個(gè)事務(wù)是一組SQL語(yǔ)句集合,Oracle把它當(dāng)作單獨(dú)的單元運(yùn)行。一個(gè)事務(wù)從第一個(gè)SQL語(yǔ)句開(kāi)始,遇到"EXEC SQL COMMIT"(執(zhí)行當(dāng)前事務(wù)對(duì)數(shù)據(jù)庫(kù)的永久修改)或"EXEC SQL ROLLBACK"(取消從事務(wù)開(kāi)始到當(dāng)前位置對(duì)數(shù)據(jù)庫(kù)的任何修改)時(shí)結(jié)束事務(wù)。當(dāng)前事務(wù)由COMMIT或ROLLBACK語(yǔ)句結(jié)束后,下一條可執(zhí)行SQL語(yǔ)句將自動(dòng)開(kāi)始一個(gè)新事務(wù)。如果程序結(jié)束時(shí)沒(méi)有執(zhí)行EXEC SQL COMMIT,則對(duì)數(shù)據(jù)庫(kù)的所作的修改都將被忽略。
--------------------------------------------------------------------------------錯(cuò)誤處理
在每個(gè)可執(zhí)行的SQL表達(dá)式之后,可以在程序中檢查SQLCA顯式地或用WHENEVER語(yǔ)句隱式地得到執(zhí)行狀態(tài)信息。下面將詳細(xì)地介紹這兩種方法。
--------------------------------------------------------------------------------SQLCA
SQLCA(SQL Communications Area,SQL通訊區(qū))用于在程序中檢查錯(cuò)誤和狀態(tài)變化。每個(gè)可執(zhí)行SQL語(yǔ)句執(zhí)行后,Oracle 運(yùn)行時(shí)會(huì)在這個(gè)結(jié)構(gòu)中填入信息。如果要使用SQLCA,你要用#include包含進(jìn)sqlca.h頭文件。如果在很多地方包含了頭文件,你要使用#undef SQLCA來(lái)取消SQLCA的宏定義。sqlca.h中的相關(guān)程序塊如下:#ifndef SQLCA
#define SQLCA 1struct sqlca {
??? /* ub1 */ char sqlcaid[8];
??? /* b4 */ long sqlabc;
??? /* b4 */ long sqlcode;
??? struct {
??????? /* ub2 */ unsigned short sqlerrml;
??????? /* ub1 */ char sqlerrmc[70];
??? } sqlerrm;
??? /* ub1 */ char sqlerrp[8];
??? /* b4 */ long sqlerrd[6];
??? /* ub1 */ char sqlwarn[8];
??? /* ub1 */ char sqlext[8];
};
/* ... */
sqlca域有下列的意義:sqlcaid 該字符串域初始化為"SQLCA",以指明這是個(gè)SQL通訊區(qū)。?
sqlcabc 該整數(shù)域用byte標(biāo)識(shí)SQLCA結(jié)構(gòu)的長(zhǎng)度。?
sqlcode 這個(gè)整數(shù)域標(biāo)識(shí)最近執(zhí)行的SQL語(yǔ)句的狀態(tài)碼:0 沒(méi)有錯(cuò)誤。?
>0 語(yǔ)句執(zhí)行但捕獲異常。當(dāng)Oracle根據(jù)WHERE條件查找不到任何記錄,或SELECT INTO或FETCH影響記錄數(shù)為0時(shí)會(huì)發(fā)生這種情況。?
<0 由于一個(gè)錯(cuò)誤Oracle不能執(zhí)行SQL語(yǔ)句。當(dāng)這個(gè)錯(cuò)誤發(fā)生時(shí),多數(shù)情況下當(dāng)前的事務(wù)應(yīng)該回滾(rollback)。?
?
sqlerrm 這個(gè)內(nèi)嵌結(jié)構(gòu)包含兩個(gè)域:?
sqlerrml - 在sqlerrmc中保存的信息文本的長(zhǎng)。?
sqlerrmc - 最大到70個(gè)字符(character)的信息文本,與sqlcode中存儲(chǔ)的錯(cuò)誤碼相似。
sqlerrp 保留?
sqlerrd 這個(gè)二進(jìn)制×××數(shù)組包含6個(gè)元素:?
sqlerrd[0] - 保留?
sqlerrd[1] - 保留?
sqlerrd[2] - 最近被執(zhí)行的SQL語(yǔ)句影響的記錄行數(shù)。?
sqlerrd[3] - 保留?
sqlerrd[4] - 分析最近執(zhí)行語(yǔ)句出現(xiàn)錯(cuò)誤,錯(cuò)誤的開(kāi)始字符的偏移。?
sqlerrd[5] - 保留
sqlwarn 這個(gè)單字符數(shù)組包含8個(gè)元素,用于警告標(biāo)志。Oracle使用字符'W'設(shè)置一個(gè)標(biāo)記。sqlwarn[0] 當(dāng)其它標(biāo)記被設(shè)置時(shí)設(shè)置。?
sqlwarn[1] 當(dāng)輸出宿主變量中保存的是被截?cái)嗟淖侄沃禃r(shí)設(shè)置。?
sqlwarn[2] 當(dāng)計(jì)算SQL統(tǒng)計(jì)如AVG或SUM時(shí),如果一個(gè)NULL字段不能被使用時(shí)被設(shè)置。?
sqlwarn[3] 當(dāng)SELECT的字段數(shù)與INTO句中指定的宿主變量數(shù)不等時(shí)設(shè)置。?
sqlwarn[4] 當(dāng)沒(méi)有使用WHERE子句的UPDATE或DELETE語(yǔ)句處理了數(shù)據(jù)表中的每一行時(shí)設(shè)置。?
sqlwarn[5] 當(dāng)由于PL/SQL編譯錯(cuò)誤而導(dǎo)致procedure/function/package/package body創(chuàng)建命令失敗時(shí)設(shè)置。?
sqlwarn[6] 不再使用?
sqlwarn[7] 不再使用?
?
sqlext 保留SQLCA只能在sqlerrm域中存儲(chǔ)最大70字符長(zhǎng)的錯(cuò)誤信息。要得到更長(zhǎng)的(或嵌套的)全部錯(cuò)誤信息字符,可以使用sqlglm()函數(shù):void sqlglm(char *msg_buf, size_t *buf_size, size_t *msg_length);
msg_buf是Oracle存儲(chǔ)錯(cuò)誤信息的字符緩沖;buf_size指定msg_buf的長(zhǎng)(byte); Oracle在*msg_length中存放實(shí)際的錯(cuò)誤信息長(zhǎng)。Oracle錯(cuò)誤信息的最大長(zhǎng)度是512字節(jié)(byte)。
--------------------------------------------------------------------------------WHENEVER語(yǔ)句
這個(gè)表達(dá)式進(jìn)行自動(dòng)錯(cuò)誤檢查和處理。語(yǔ)法是:EXEC SQL WHENEVER? ;
Oracle自動(dòng)檢查的SQLCA,當(dāng)條件被檢測(cè)到時(shí),程序會(huì)自動(dòng)執(zhí)行可以是下列各項(xiàng):SQLWARNING - 由于Oracle返回一個(gè)警告而設(shè)置sqlwarn[0]?
SQLERROR - 由于Oracle返回一個(gè)錯(cuò)誤, sqlcode的值為負(fù)?
NOT FOUND - 由于Oracle按WHERE的條件沒(méi)有找到任何一條記錄,或SELECT INTO或FETCH返回0條記錄,而使sqlcode為正
可以為下列各項(xiàng):CONTINUE - 只要可能,程序會(huì)嘗試?yán)^續(xù)運(yùn)行之后的語(yǔ)句?
DO - 程序?qū)⒖刂茩?quán)交給一個(gè)錯(cuò)誤處理模塊?
GOTO - 程序跳轉(zhuǎn)到被標(biāo)示的語(yǔ)句?
STOP - 調(diào)用exit()結(jié)束程序,回滾未提交的操作
下面是WHENEVER語(yǔ)句的例子:EXEC SQL WHENEVER SQLWARNING DO print_warning_msg();
EXEC SQL WHENEVER NOT FOUND GOTO handle_empty;
下面是一個(gè)更詳細(xì)的例子:/* code to find student name given id */
/* ... */
for (;;)
{
??? printf("Give student id number : ");
??? scanf("%d", &id);
??? EXEC SQL WHENEVER NOT FOUND GOTO notfound;
??? EXEC SQL SELECT studentname INTO :st_name
???????????? FROM?? student
???????????? WHERE? studentid = :id;
??? printf("Name of student is %s. ", st_name);
??? continue;
notfound:
??? printf("No record exists for id %d! ", id);
}
/* ... */
注意WHENEVER表達(dá)式不遵從標(biāo)準(zhǔn)C的作用域規(guī)則,整個(gè)程序都是它的作用域。舉例來(lái)說(shuō),如果下面的語(yǔ)句在你程序中的什么地方(如在一個(gè)循環(huán)之前):EXEC SQL WHENEVER NOT FOUND DO break;?
這個(gè)文件在這行之后出現(xiàn)的所有SQL語(yǔ)句都會(huì)受其影響。當(dāng)不再需要WHENEVER 的來(lái)影響程序時(shí)(比如在你的循環(huán)之后),確保使用下面的語(yǔ)句取消它的使用。EXEC SQL WHENEVER NOT FOUND CONTINUE;
--------------------------------------------------------------------------------Demo程序
注意: 例程會(huì)創(chuàng)建、使用四個(gè)表:DEPT、EMP、PAY1和PAY2。注意你的數(shù)據(jù)庫(kù)中可能會(huì)存在相同名子的表!在leland系統(tǒng)的/afs/ir/class/cs145/code/proc下有很多例程。它們被命名為sample*.pc(C用戶)和cppdemo*.pc(C++用戶)。 ".pc"是Pro*C代碼的擴(kuò)展名。由于有幾個(gè)固定的步驟復(fù)制這些文件,所以不要手工復(fù)制它們。下面介紹如何下載和設(shè)置例程:確認(rèn)你已經(jīng)運(yùn)行了source /afs/ir/class/cs145/all.env?
在你的目錄下,運(yùn)行l(wèi)oad_samples , 是你想放置例程的地方(例:load_samples sally etaoinshrdlu cs145_samples )?
cd?
運(yùn)行make samples(C++用戶運(yùn)行make cppsamples)編譯所有的例程。
第2步將會(huì)建立樣品數(shù)據(jù)庫(kù),創(chuàng)建在指定的新目錄,然后把文件復(fù)制到目錄下。它會(huì)在例程中修改你的用戶名和密碼,所有你不必每次運(yùn)行例程時(shí)都要輸入用戶名和密碼。sample1 和cppdemo1也為用戶提供了輸入用戶名和密碼的接口,當(dāng)你想要學(xué)習(xí)如何使用的時(shí)候。如果在第2步輸入用戶名和密碼時(shí)產(chǎn)生了任何錯(cuò)誤,只要在你的目錄下運(yùn)行clean_sample & lt;sample_dir>,然后重做第2步到第4步。對(duì)于第4步,你可以單獨(dú)編譯每一個(gè)例程。比如單獨(dú)編譯sample1.pc。編譯過(guò)程實(shí)際上有兩句:proc iname=sample1.pc
把內(nèi)嵌SQL代碼轉(zhuǎn)換為相應(yīng)的庫(kù)調(diào)用,輸出sample1.c?
cc sample1.c
主成可執(zhí)行的sample1
編譯你自己的代碼,如foo.pc,只要修改Makefile的幾個(gè)變量:在SAMPLES變量中加入foo程序名,在SAMPLE_SRC變量中加入foo.pc源文件名。然后,寫(xiě)好foo.pc 后make foo。foo.pc被預(yù)編譯為foo.c,再編譯為可執(zhí)行的foo。C++用戶要把程序名和源文件名加入到CPPSAMPLE和CPPSAMPLE_SRC而不是SAMPLES和SAMPLE_SRC。例程運(yùn)行于下面的數(shù)據(jù)庫(kù)表上:CREATE TABLE DEPT
??? (DEPTNO??? NUMBER(2) NOT NULL,
???? DNAME???? VARCHAR2(14),
???? LOC?????? VARCHAR2(13));CREATE TABLE EMP
??? (EMPNO???? NUMBER(4) NOT NULL,
???? ENAME???? VARCHAR2(10),
???? JOB?????? VARCHAR2(9),
???? MGR?????? NUMBER(4),
???? HIREDATE? DATE,
???? SAL?????? NUMBER(7, 2),
???? COMM????? NUMBER(7, 2),
???? DEPTNO??? NUMBER(2));CREATE TABLE PAY1
??? (ENAME???? VARCHAR2(10),
???? SAL?????? NUMBER(7, 2));CREATE TABLE PAY2
??? (ENAME???? VARCHAR2(10),
???? SAL?????? NUMBER(7, 2));
當(dāng)在第2步運(yùn)行l(wèi)oad_samples的時(shí)候這些表就自動(dòng)創(chuàng)建好了。一些tuples(譯注:沒(méi)找到合適的詞,把原詞放這了)也插入了。你可以在程序運(yùn)行前查看這些表也可以任意操作這些表(如:插入、刪除或是更新tuples)。當(dāng)你運(yùn)行clean_sample時(shí),這些表自動(dòng)被刪除。注意:clean_sample也會(huì)清理整個(gè);;確保在運(yùn)行這個(gè)命令之前將你自己的文件轉(zhuǎn)移到其它的地方!你應(yīng)該在運(yùn)行它之前看一看源代碼,頭部的注釋描述了程序都做些什么。例如,sample1從一個(gè)雇員的EMPNO 得到他的名子和工資,從EMP表中得到的那個(gè)雇員的傭金。通過(guò)學(xué)習(xí)源程序你應(yīng)該可以學(xué)到下面的東西:如何從主機(jī)連接到Oracle?
如何在C/C++中嵌入SQL?
如何使用游標(biāo)?
如何使用宿主變量與數(shù)據(jù)庫(kù)通訊?
如何使用WHENEVER進(jìn)行不同的錯(cuò)誤處理動(dòng)作?
如何使用指示器變量檢測(cè)輸出中的空值
現(xiàn)在,你可以使用這些技術(shù)編寫(xiě)你自己的數(shù)據(jù)庫(kù)應(yīng)用程序了。And have fun!
--------------------------------------------------------------------------------C++用戶
要使用預(yù)編譯器生成合適的C++代碼,你需要注意下面的事項(xiàng):代碼被預(yù)編譯器展開(kāi)。要得到C++代碼,你需要在執(zhí)行proc時(shí)設(shè)置CODE=CPP選項(xiàng)。
解析能力。proc的PARSE選項(xiàng)可以是下面的值:
PARSE=NONE. C預(yù)處理指令只能在聲明節(jié)中被解析,所以所有的宿主變量需要在聲明節(jié)中聲明。
PARSE=PARTIAL. C預(yù)處理指令能被解析;然而,所有的宿主變量需要在聲明節(jié)中聲明。
PARSE=FULL. C預(yù)處理指令能被解析,而且宿主變量可以聲明在任何地方。當(dāng)CODE不為 CPP時(shí),這是默認(rèn)設(shè)置;但當(dāng)CODE=CPP時(shí),指定PARSE=FULL卻是個(gè)錯(cuò)誤。
所以,C++用戶必須指定PARSE=NONE或PARSE=PARTIAL,因此這也失去了在任意地方聲明宿主變量的自由。更有,宿主變量必須被包在一個(gè)聲明節(jié)中,如下:?
EXEC SQL BEGIN DECLARE SECTION;
??? // declarations...
EXEC SQL END DECLARE SECTION;
你需要使用這種方法去聲明所有的宿主和指示器變量。
文件擴(kuò)展名。你要指定設(shè)置CPP_SUFFIX=cc或CPP_SUFFIX=C。
頭文件定位。默認(rèn)情況下,proc像標(biāo)準(zhǔn)定位stdio.h文件一樣查找頭文件。然而C++有自己的頭文件,如iostream.h,被放置在別處。所以,你需要使用SYS_INCLUDE選項(xiàng)指定proc查找頭文件的路徑。--------------------------------------------------------------------------------Pro*C支持的嵌入SQL語(yǔ)句列表
聲明表達(dá)式?
EXEC SQL ARRAYLEN 在PL/SQL中使用宿主變量?
EXEC SQL BEGIN DECLARE SECTION?
EXEC SQL END DECLARE SECTION 聲明宿主變量?
EXEC SQL DECLARE 給Oracle對(duì)像命名?
EXEC SQL INCLUDE 從文件中復(fù)制?
EXEC SQL TYPE 同等化數(shù)據(jù)類型?
EXEC SQL VAR 同等化變量?
EXEC SQL WHENEVER 處理運(yùn)行時(shí)錯(cuò)誤?
執(zhí)行表達(dá)式?
EXEC SQL ALLOCATE 聲明、控制Oracle數(shù)據(jù)?
EXEC SQL ALTER?
EXEC SQL ANALYZE?
EXEC SQL AUDIT?
EXEC SQL COMMENT?
EXEC SQL CONNECT?
EXEC SQL CREATE?
EXEC SQL DROP?
EXEC SQL GRANT?
EXEC SQL NOAUDIT?
EXEC SQL RENAME?
EXEC SQL REVOKE?
EXEC SQL TRUNCATE?
EXEC SQL CLOSE?
EXEC SQL DELETE 排序、修改Oracle數(shù)據(jù)?
EXEC SQL EXPLAIN PLAN?
EXEC SQL FETCH?
EXEC SQL INSERT?
EXEC SQL LOCK TABLE?
EXEC SQL OPEN?
EXEC SQL SELECT?
EXEC SQL UPDATE?
EXEC SQL COMMIT 處理事務(wù)?
EXEC SQL ROLLBACK?
EXEC SQL SAVEPOINT?
EXEC SQL SET TRANSACTION?
EXEC SQL DESCRIBE 使用動(dòng)態(tài)SQL?
EXEC SQL EXECUTE?
EXEC SQL PREPARE?
EXEC SQL ALTER SESSION 控制會(huì)話?
EXEC SQL SET ROLE?
EXEC SQL EXECUTE?
END-EXEC 內(nèi)嵌PL/SQL塊
PROC是ORACLE數(shù)據(jù)庫(kù)提供的編程接口之一,其應(yīng)用十分的廣泛,本文通過(guò)一個(gè)具體的例子,介紹PROC編程的一些經(jīng)驗(yàn)及應(yīng)注意的地方。
例子程序:#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sqlda.h>
#include <sqlcpr.h>
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;
/*錯(cuò)誤處理函數(shù)*/
void sql_error(char *msg)
{
printf(" %s,%ld,%s ", 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ù)庫(kù)*/
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 ",al_empno,ac_ename,ac_hiredate,af_sal);????
}????
EXEC SQL CLOSE cur_emp;
EXEC SQL ROLLBACK WORK RELEASE;
} 1、宿主變量的聲明?
在PROC中,在SQL語(yǔ)句中用到的變量稱為宿主變量。他們應(yīng)在EXEC SQL BEGIN DECLARE SECTION;與EXEC SQL EDN DECLARE SECTION;?
之間聲明,如上面所示.在聲明宿主變量時(shí)應(yīng)注意以下幾點(diǎn):?
(1) 在數(shù)據(jù)庫(kù)表中定義為VARCHAR2,VARCHAR,CHAR的字段,在PROC中可聲明為CHAR,但長(zhǎng)度應(yīng)為它們?cè)诒碇卸x的長(zhǎng)度加1,因?yàn)镻ROC中?
CHAR型變量用做結(jié)尾。?
?
如:ENAME在表中的定義為ename varchar2(10),在PROC中可定義為:?
EXEC SQL BEGIN DECLARE SECTION;?
char ename[11];?
EXEC SQL END DECLARE SECTION;?
常見(jiàn)錯(cuò)誤說(shuō)明:?
如果插入的字符串長(zhǎng)度大于10,如:EXEC SQL INSERT INTO EMP(ENAME) VALUES('12345678901');會(huì)出現(xiàn)以下錯(cuò)誤:?
error:ORA-01480: STR 賦值變量缺少空后綴。?
?
如果定義為:?
EXEC SQL BEGIN DECLARE SECTION;?
char ename[15];?
EXEC SQL END DECLARE SECTION;?
?
當(dāng)插入的字符串長(zhǎng)度大于10,小于15時(shí),如:EXEC SQL INSERT INTO EMP(ENAME) VALUES('12345678901');會(huì)出現(xiàn)以下錯(cuò)誤:?
error:ORA-01401: 插入的值對(duì)于列過(guò)大。?
當(dāng)插入的字符串長(zhǎng)度大于15,如:EXEC SQL INSERT INTO EMP(ENAME) VALUES('12345678901234');會(huì)出現(xiàn)以下錯(cuò)誤:?
error:ORA-01401:STR 賦值變量缺少空后綴。?
?
(2) 從SQL語(yǔ)句中取字段的值到宿主變量中時(shí),PROC不會(huì)自動(dòng)給宿主變量去掉右空格。而是以在DECLARE SECTION 中定義的長(zhǎng)度為準(zhǔn)(與 表中定義的無(wú)關(guān))不足補(bǔ)右空格.如果不注意這一點(diǎn),在PROC中進(jìn)行字符串操作時(shí)(如比較相等)會(huì)出錯(cuò)。如:?
EXEC SQL BEGIN DECLARE SECTION;?
char ename[10];?
EXEC SQL END DECLARE SECTION;??
如果ENAME在表中的值為'abc',則取出的值為'abc ';?
?
可用語(yǔ)句EXEC SQL VAR重定義CHAR型變量。這樣宿主變量會(huì)自動(dòng)去掉右空格。如下:??
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) 對(duì)浮點(diǎn)型的變量,為保證精度,最好是聲明成DOUBLE型的.因?yàn)镈OUBLE型的精度比FLOAT型高很多.?
(4) 整型可聲明為L(zhǎng)ONG型(對(duì)較長(zhǎng)的整型,而且所用的平臺(tái)支持的話,如在SUN平臺(tái)上,可聲明為L(zhǎng)ONG LONG型).?
(5) DATE型的處理:DATE型一般聲明為CHAR(20)。?
往表中插入DATE型數(shù)據(jù)時(shí),一般用TO_DATE()函數(shù)進(jìn)行類型轉(zhuǎn)換,取出值時(shí)一般用TO_CHAR()函數(shù)進(jìn)行類型轉(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ù)之外聲明,則他們是全局變量。在使用之前要注意把變量的值初始化,宿主變量也可以在某個(gè)函數(shù)的內(nèi)部定義。 這時(shí)他們是局部變量。一般都習(xí)慣把宿主變量聲明為全局變量。?
?
3、數(shù)據(jù)庫(kù)的連接與斷開(kāi)?
數(shù)據(jù)庫(kù)的連接有以下兩種方法:?
(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;?
注意:在有些平臺(tái)上兩種都可以,在有些平臺(tái)上只能用第一種方法.?
在PROC程序中,要記住用EXEC SQL ROLLBACK WORK RELEASE;斷開(kāi)與數(shù)據(jù)庫(kù)的連接,并釋放相關(guān)的數(shù)據(jù)庫(kù)資源。?
?
?
4、PROC中的NULL值的處理?
如果某一字段取出的值是NULL,會(huì)報(bào):sqlcode=-1405, sqlerr=ORA-01405: 讀取的列值為 NULL?
并且相應(yīng)的宿主變量的值不會(huì)被改變,為執(zhí)行該SQL語(yǔ)句之前的值. 常用的處理NULL值的方法有:?
(1)采用指示器變量,此時(shí)不會(huì)有-1405錯(cuò)誤,當(dāng)必須是所以為NULL的字段都有相應(yīng)的指示器變量,如果某一字段沒(méi)有指示器變量,但取出的值?
為NULL值,則仍然會(huì)有-1405錯(cuò)誤.當(dāng)取出的值是NULL時(shí),相應(yīng)的指示器變量變量為-1,可根據(jù)指示器變量的值做響應(yīng)的處理。?
(2)如果字段較多,可取字段到一個(gè)結(jié)構(gòu)體中及與該結(jié)構(gòu)體對(duì)應(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,會(huì)為"",整型的NULL會(huì)為0,?
浮點(diǎn)型的會(huì)為0.00。此時(shí)不會(huì)有-1405錯(cuò)誤。?
(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;?
這樣也不會(huì)有-1405錯(cuò)誤不,當(dāng)取出的值是NULL時(shí),自動(dòng)用NVL()中指定的值代替.?
CHR(0)也可直接用''代替,如下:?
SELECT EMPNO, NVL(ENAME,''),nvl(to_char(HIREDATE,'yyyy/mm/dd hh24:mi:ss'),''),NVL(SAL,0) FROM EMP;?
?
?
5、PROC中的錯(cuò)誤的處理?
所有的SQL語(yǔ)句都有可能出錯(cuò).所以都要加以判斷,但每個(gè)SQL語(yǔ)句后都加錯(cuò)誤判斷,太麻煩,可用一個(gè)函數(shù)如sql_error()來(lái)進(jìn)行錯(cuò)誤處理,?
方法:?
(1)定義ql_error()函數(shù)。?
(2)在開(kāi)頭加上EXEC SQL WHENEVER SQLERROR DO sql_error();這樣當(dāng)發(fā)生sqlca.sqlcode <0 的錯(cuò)誤時(shí),程序自動(dòng)轉(zhuǎn)到sql_error()中執(zhí)行. 注意:對(duì)sqlca.sqlcode >0的錯(cuò)誤如 sqlca.sqlcode =1403 是不會(huì)轉(zhuǎn)到sql_error()中執(zhí)行的.?
另外:在UNIX下,可以用OERR 來(lái)查找錯(cuò)誤的描述。如: ora ORA -1405 查找錯(cuò)誤號(hào)為-1405的描述.?
?
?
6、PROC中調(diào)用存儲(chǔ)過(guò)程的方法?
要把存儲(chǔ)過(guò)程放在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存儲(chǔ)過(guò)程出錯(cuò),errno=%ld,errtext=%s ",l_errno,c_errtext);?
}?
?
7、PROC的命令行選項(xiàng):PROC編譯器有很多的命令行選項(xiàng),在命令行下直接不帶參數(shù)運(yùn)行PROC,會(huì)列出所有的命令行選項(xiàng)來(lái),并有說(shuō)明。?
(1)儲(chǔ)存過(guò)程:編譯儲(chǔ)存過(guò)程是要帶上用戶名及密碼?
proc USERID=scott/tiger sqlcheck=SEMANTICS ireclen=512 iname=test.cpp?
(2)PARSE=NONE 對(duì)非SQL代碼不進(jìn)行語(yǔ)法分析,默認(rèn)對(duì)非SQL代碼也進(jìn)行語(yǔ)法分析.?
在RED HAD6.3上的ORACLE8.1.5中用PROC時(shí),會(huì)提示:/USR/INCLUDE/STDIO.H 及其他的.H文件中有錯(cuò). 可把PARSE=NONE加上,就好了.?
?
?
8、注意加上:EXEC ORACLE OPTION (RELEASE_CURSOR = YES);?
RELEASE_CURSOR=YES 使PROC 在執(zhí)行完后釋放與嵌入SQL有關(guān)資源,保證在該P(yáng)ROC程序執(zhí)行完后,ORACLE不會(huì)鎖住數(shù)據(jù)庫(kù)資源,如鎖表等。?
如果在PROC中用到ORACA,還要在程序頭加上:?
EXEC ORACLE OPTION (ORACA=YES);?
?
9、PROC中的類型轉(zhuǎn)換?
一、在C語(yǔ)言中:?
(1)字符型到整型可用ATOI() ATOL(),SSCANF()?
(2)整型,浮點(diǎn)型到字符型,可用SPRINTF()?
(3)字符型到浮點(diǎn)型用ATOF()不行,最好用SSCANF(),舉例如下:?EXEC SQL BEGIN DECLARE SECTION;
double d_demo;
float f_demo;
char ac_text[20]="222";
EXEC SQL END DECLARE SECTION;????
(1)sscanf(ac_text, "%f", &d_demo);
printf("ac_text=%s,d_demo=%f ",ac_text,d_demo);
(2)sscanf(ac_text, "%lf", &d_demo);
printf("ac_text=%s,d_demo=%f ",ac_text,d_demo);
(3)sscanf(ac_text, "%f", &d_demo);
printf("ac_text=%s,d_demo=%lf ",ac_text,d_demo);
(4)sscanf(ac_text, "%lf", &d_demo);
printf("ac_text=%s,d_demo=%lf ",ac_text,d_demo);
printf("******************* ");
(5)sscanf(ac_text, "%f", &f_demo);
printf("ac_text=%s,f_demo=%f ",ac_text,f_demo);
(6)sscanf(ac_text, "%lf", &f_demo);
printf("ac_text=%s,f_demo=%f ",ac_text,f_demo);
(7)sscanf(ac_text, "%f", &f_demo);
printf("ac_text=%s,f_demo=%lf ",ac_text,f_demo);
(8)sscanf(ac_text, "%lf", &f_demo);
printf("ac_text=%s,f_demo=%lf ",ac_text,f_demo);
輸出的結(jié)果:????
ac_text=222.00,d_demo=0.000000????
ac_text=222.00,d_demo=222.000000????
ac_text=222.00,d_demo=222.000032????
ac_text=222.00,d_demo=222.000000????
*******************????
ac_text=222.00,f_demo=222.000000????
ac_text=222.00,f_demo=0.000000????
ac_text=222.00,f_demo=222.000000????
ac_text=222.00,f_demo=0.000000????
d_demo=atof(ac_text);
printf("ac_text=%s,atof(ac_text)=%f ",ac_text,d_demo);
d_demo=atof(ac_text);
printf("ac_text=%s,atof(ac_text)=%lf ",ac_text,d_demo);
f_demo=atof(ac_text);
printf("ac_text=%s,atof(ac_text)=%f ",ac_text,f_demo);
f_demo=atof(ac_text);
printf("ac_text=%s,atof(ac_text)=%lf ",ac_text,f_demo);
輸出的結(jié)果:????
ac_text=222.00,atof(ac_text)=1243288.000000
ac_text=222.00,atof(ac_text)=1243288.000000
ac_text=222.00,atof(ac_text)=1243288.000000
ac_text=222.00,atof(ac_text)=1243288.000000
從上面的結(jié)果可見(jiàn):?
DOUBLE型應(yīng)采用sscanf(ac_app_capcity, "%lf", &d_app); 打印用"%lf","%f" 都可以. (2),(4)正確?
FLOAT型應(yīng)采用sscanf(ac_app_capcity, "%f", &d_app); 打印用"%lf","%f" 都可以. (5),(7)正確?
采用ATOF()轉(zhuǎn)換的結(jié)果都是錯(cuò)的,所以不要用它。?
?
二、寫(xiě)表或從表中取數(shù)據(jù)時(shí):?
(1)字符型與整型之間可不用轉(zhuǎn)換,采用默認(rèn)方式。?
(2)字符型與浮點(diǎn)型之間可不用轉(zhuǎn)換,采用默認(rèn)方式。?
(3)日期型與字符型之間可用TO_CHAR(),TO_DATE()。?
?
?
10、PROC中的4種動(dòng)態(tài)SQL簡(jiǎn)介?
(1)動(dòng)態(tài)SQL1: 不能是查詢(SELECT)語(yǔ)句,并且沒(méi)有宿主變量.??
用法:拼一串動(dòng)態(tài)SQL語(yǔ)句,并用EXECUTE IMMEDIATE執(zhí)行,如:?
EXEC SQL EXECUTE IMMEDIATE "CREATE TABLE dyn1 (col1 VARCHAR2(4))";?
?
(2)動(dòng)態(tài)SQL2: 不能是查詢(SELECT)語(yǔ)句,并且輸入的宿主變量數(shù)目是知道的,?
用法:拼一串動(dòng)態(tài)SQL語(yǔ)句,用PREPARE,EXECUTE語(yǔ)句執(zhí)行.?
strcpy(c_sql, "DELETE FROM EMP WHERE EMPNO = :?");??
EXEC SQL PREPARE sql_stmt FROM :c_sql;?
EXEC SQL EXECUTE sql_stmt USING :emp_number;??
?
(3)動(dòng)態(tài)SQL3: 用于創(chuàng)建動(dòng)態(tài)查詢, 并且要查詢的字段及輸入的宿主變量數(shù)目是知道的?
用法: 拼一串動(dòng)態(tài)SQL語(yǔ)句,用PREPARE分析該語(yǔ)句,并要定義一個(gè)CURSOR進(jìn)行取值?
如:如要查詢的數(shù)據(jù)按一年12月放到12張表中。表名為user_fee_1mon, user_fee_2mon,....可采用動(dòng)態(tài)SQL3來(lái)進(jìn)行查詢?strcpy(c_sql,"select c_user_id,c_user_name,to_char(t_date,'yyyy/mm/dd hh:mi:ss'),n_fee ");
strcat(c_sql,"from USER_FEE_");
strcat(c_sql,ac_mon);
strcat(c_sql," where c_user_id = :v1");
EXEC SQL PREPARE s FROM :c_sql;
EXEC SQL DECLARE cur_user_fee CURSOR FOR s;
EXEC SQL OPEN cur_user_fee USING :ac_user_id;
while(1)
{????
EXEC SQL FETCH cur_user_fee into :c_user_id,:c_user_name,:c_date,:n_fee);
if (sqlca.sqlcode < 0)
{????
/*FETCH CURSOR失敗*/????
printf("fetch cursor cur_user_fee fail,sqlcode=%ld,sqlserr=%s",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
}
if( sqlca.sqlcode == SQLNOTFOUND)
{
break;
}
}
EXEC SQL CLOSE cur_user_fee;????(4)動(dòng)態(tài)SQL4:要處理的字段及輸入的宿主變量數(shù)目和主變量的類型事先是不知道的,如:?
INSERT INTO EMP (<unknown>) VALUES (<unknown>)?
是最復(fù)雜的動(dòng)態(tài)SQL,很少用,在此不做介紹。?
?
?
11、SQLCA:SQL是ORACLE的一個(gè)結(jié)構(gòu)體,它的域用于最近的一條SQL語(yǔ)句執(zhí)行后的一些信息,如錯(cuò)誤號(hào),錯(cuò)誤描述,警告,狀態(tài)等。常用的?
域介紹如下:?
SQLCA.sqlcode:錯(cuò)誤號(hào),=0正確,=1403沒(méi)取到數(shù)據(jù)?
SQLCA.sqlserrm.sqlerrmc:錯(cuò)誤描述?
SQLCA.sqlerrd[3]:最近的一條SQL語(yǔ)句所處理的行數(shù),如果該語(yǔ)句處理失敗,則它的值是不定的,如果錯(cuò)誤在一個(gè)CURSOR操作中發(fā)生,則?
它的值指已成功處理的行數(shù).在DELETE,UPDATE中,它不包含因外鍵約束而刪除,更新的那些行,??
DELETE FROM EMP WHERE DEPT='SALE';?
在表EMP中刪除20行,但如果表EMP與表ADDRESS有外鍵約束,導(dǎo)致表ADDRESS也被刪除20行,則SQLCA.sqlerrd[3]=20,而不是40。------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Pro*C介紹-內(nèi)嵌SQL?
[ Translate by Z.Jingwei. Document address:http://www-db.stanford.edu/~ullman/fcdb/oracle/or-proc.html?]?
Pro*C介紹
內(nèi)嵌SQL--------------------------------------------------------------------------------概要?
Pro*C語(yǔ)法?
SQL?
預(yù)處理指令?
語(yǔ)句標(biāo)號(hào)?
宿主變量?
基礎(chǔ)?
指針?
結(jié)構(gòu)?
數(shù)組?
指示器變量?
數(shù)據(jù)類型同等化?
動(dòng)態(tài)SQL?
事務(wù)?
錯(cuò)誤處理?
SQLCA?
WHENEVER語(yǔ)句?
Demo程序?
C++用戶?
List of Embedded SQL Statements Supported by Pro*C--------------------------------------------------------------------------------概要
內(nèi)嵌SQL是結(jié)合高級(jí)語(yǔ)言如C/C++的計(jì)算能力和SQL數(shù)據(jù)庫(kù)處理能力的一種方法。它允許你在程序中執(zhí)行任意的SQL語(yǔ)句。Oracle的嵌入SQL環(huán)境稱為Pro*C。Pro*C程序分兩步編譯。首先,Pro*C的預(yù)編譯器識(shí)別出嵌入在程序中的SQL語(yǔ)句,并將這些語(yǔ)句轉(zhuǎn)換為對(duì)SQL運(yùn)行時(shí)庫(kù)(SQL runtime library)中功能(functions)的適當(dāng)調(diào)用。輸出是純C/C++代碼和未被處理的純C/C++代碼。然后,用常規(guī)C/C++編譯器編譯代碼并生成可執(zhí)行程序。更詳細(xì)的內(nèi)容請(qǐng)參考Demo程序。Demo程序。
--------------------------------------------------------------------------------Pro*C語(yǔ)法--------------------------------------------------------------------------------SQL
所有SQL語(yǔ)句都要以EXEC SQL開(kāi)始,并用分號(hào)";"結(jié)束。SQL語(yǔ)句可以放置在C/C++塊中的任何地方,但可執(zhí)行的(SQL)語(yǔ)句應(yīng)該在聲明語(yǔ)句后面。例:{
??? int a;
??? /* ... */
??? EXEC SQL SELECT salary INTO :a
???????????? FROM Employee
???????????? WHERE SSN=876543210;
??? /* ... */
??? printf("The salary is %d ", a);
??? /* ... */
}
--------------------------------------------------------------------------------預(yù)處理指令
能夠在Pro*C中正常工作的C/C++預(yù)處理指令是#include和#if。Pro*C不能識(shí)別#define。下面的代碼是錯(cuò)誤的:#define THE_SSN 876543210
/* ... */
EXEC SQL SELECT salary INTO :a
???????? FROM Employee
???????? WHERE SSN = THE_SSN;/* INVALID */--------------------------------------------------------------------------------語(yǔ)句標(biāo)號(hào)
可以在SQL中跳轉(zhuǎn)到C/C++標(biāo)記EXEC SQL WHENEVER SQLERROR GOTO error_in_SQL;
??? /* ... */
error_in_SQL:
??? /* do error handling */
我們會(huì)在后面的錯(cuò)誤處理一節(jié)中講到有關(guān)WHENEVER的含意。錯(cuò)誤處理一節(jié)中講到有關(guān)WHENEVER的含意。
--------------------------------------------------------------------------------宿主變量--------------------------------------------------------------------------------基礎(chǔ)
宿主變量是連接宿主程序與數(shù)據(jù)庫(kù)的關(guān)鍵。宿主變量表達(dá)式必須視為(resolve to)左值(能被賦值)。你可以像聲明普通C變量一樣,按著C的語(yǔ)法規(guī)則聲明宿主變量。宿主變量的聲明可以放置在任何C變量聲明可以放置的地方。(C++用戶需要使用"DECLARE SECTION";參考C++ Users) Oracle可以使用的C數(shù)據(jù)類型包括:C++ Users) Oracle可以使用的C數(shù)據(jù)類型包括:
char?
char[n]?
int?
short?
long?
float?
double?
VARCHAR[n] - 它是能被Pro*C的預(yù)編譯器識(shí)別的預(yù)處理類型(psuedo-type)。它用來(lái) 表示由空白填充(blank-padded,譯注:'')的變長(zhǎng)字符串。Pro*C預(yù)編譯器會(huì)把它轉(zhuǎn)換為有一個(gè)2字節(jié)(byte)長(zhǎng)的域和一個(gè)n字(byte)長(zhǎng)的字符數(shù)組的結(jié)構(gòu)體。?
你不能指定寄存器存儲(chǔ)類型(譯注:指針)為宿主變量。可以在SQL表達(dá)式中使用冒號(hào)":"做前綴來(lái)引用一個(gè)宿主變量,但不能在C表達(dá)式中用分號(hào)做前綴。當(dāng)使用字符串作為宿主變量時(shí),必須省略引用;Pro*C明白你正指定一個(gè)基于宿主變量聲明類型的字符串(譯注:這句的意思是,當(dāng)定義一個(gè)字符串做為宿主變量時(shí)char *str="string",在嵌入SQL中使用時(shí),要省略"*"而不是*str)。不能將C函數(shù)調(diào)用和多數(shù)的指針計(jì)算表達(dá)式作為宿主變量使用,即使它們確實(shí)被解釋為左值。下面的代碼同時(shí)說(shuō)明了合法和不合法的宿主變量的引用:int deptnos[3] = { 000, 111, 222 };
int get_deptno() { return deptnos[2]; }
int *get_deptnoptr() { return &(deptnos[2]); }
int main()?
{
??? int x; char *y; int z;
??? /* ... */
??? EXEC SQL INSERT INTO emp(empno, ename, deptno)
??????? VALUES(:x, :y, :z); /* LEGAL */
??? EXEC SQL INSERT INTO emp(empno, ename, deptno)
??????? VALUES(:x + 1,? /* LEGAL: the reference is to x */
?????????????? 'Big Shot',? /* LEGAL: but not really a host var */
?????????????? :deptnos[2]);/* LEGAL: array element is fine */
??? EXEC SQL INSERT INTO emp(empno, ename, deptno)
??????? VALUES(:x, :y,
?????????????? :(*(deptnos+2)));/* ILLEGAL: although it has anlvalue */
??? EXEC SQL INSERT INTO emp(empno, ename, deptno)
??????? VALUES(:x, :y,
?????????????? :get_deptno());? /* ILLEGAL: no function calls */
??? EXEC SQL INSERT INTO emp(empno, ename, deptno)
??????? VALUES(:x, :y,
?????????????? :(*get_depnoptr())); /* ILLEGAL: although it has an lvalue */
??? /* ... */
}
--------------------------------------------------------------------------------指針
可以在SQL表達(dá)式中使用普通C語(yǔ)法聲明的指針。通常使用一個(gè)冒號(hào)做前綴:int*x;
/*...*/
EXEC SQL SELECT xyz INTO :x FROM ...;
這個(gè)SELECT語(yǔ)句的結(jié)果會(huì)寫(xiě)入*x,而不是x。
--------------------------------------------------------------------------------結(jié)構(gòu)
結(jié)構(gòu)同樣可以作為宿主變量使用,如下面例子:typedef struct {
??? char name[21];/* one greater than column length; for '' */
??? int SSN;
} Emp;
/* ... */
Emp bigshot;
/* ... */
EXEC SQL INSERT INTO emp (ename, eSSN)
??? VALUES (:bigshot);
--------------------------------------------------------------------------------數(shù)組
像下面這樣使用宿主數(shù)組:int emp_number[50];
char name[50][11];
/* ... */
EXEC SQL INSERT INTO emp(emp_number, name)
??? VALUES (:emp_number, :emp_name);
這樣會(huì)一次插入所有的50個(gè)元素(tuples)。數(shù)組只能是一維數(shù)組。例子中的char name[50][11]可能看起來(lái)與這個(gè)規(guī)則矛盾,然而,Pro*C實(shí)際上把name視為一維字符串?dāng)?shù)組而不是二維字符數(shù)組。也可以使用結(jié)構(gòu)數(shù)組。當(dāng)使用數(shù)組存放查詢結(jié)果時(shí),如果宿主數(shù)組的大小(n)小于實(shí)際查詢后返回的結(jié)果數(shù)量時(shí),那么只有(查詢出來(lái)的)前n個(gè)結(jié)果被填入宿主數(shù)組。
--------------------------------------------------------------------------------指示器變量
指示器實(shí)際上是附在宿主變量后的"NULL標(biāo)記"。每一個(gè)宿主變量都可以選擇性的關(guān)聯(lián)到一個(gè)指示器變量上。指示器變量的類型必須為2字節(jié)×××值(short類型),而且必須緊隨在宿主變量后且用冒號(hào)做為前綴。你也可以使用關(guān)鍵字INDICATOR放在宿主變量和指示器變量之間。例如:short indicator_var;
EXEC SQL SELECT xyz INTO :host_var:indicator_var
??? FROM ...;
/* ... */
EXEC SQL INSERT INTO R
??? VALUES(:host_var INDICATOR :indicator_var, ...);
在SELECT的INTO子句中使用的指示器變量可以用來(lái)檢查返回給宿主變量的值為空(NULL)或被截?cái)嗟牡那闆r。Oracle能夠賦給指示器變量的值具有下面各項(xiàng)意義:-1 字段(譯注:原文為column,意為該字段的列)值為NULL,宿主變量的值不確定。?
0 Oracle把完整的字值賦給了宿主變量。?
>0 Oracle把被截?cái)嗟淖侄沃蒂x給了宿主變量。指示器變量返回的×××值是字段的原始長(zhǎng)度。?
-2 Oracle把被截?cái)嗟淖侄沃蒂x給了宿主變量,但原字段值是不確定的。(譯注:這種情況可能是數(shù)值型的值被切斷后不能確定原始值)你也可以在INSERT或UPDATE的VALUES和SET子句中使用指示器變量指明用于輸入的宿主變量為NULL值。你的程序可以賦給指示器變量的值具有如下各項(xiàng)意義:-1 Oracle會(huì)忽略宿主變量的值并給字段賦一個(gè)NULL值。?
>=0 Oracle會(huì)將宿主變量的值賦給字段。
--------------------------------------------------------------------------------數(shù)據(jù)類型同等化
Oracle認(rèn)識(shí)兩種數(shù)據(jù)類型:內(nèi)部類型和外部類型。內(nèi)部數(shù)據(jù)類型指示Oracle在數(shù)據(jù)庫(kù)表中如何存儲(chǔ)字段。外部數(shù)據(jù)類型指示如何格式化存儲(chǔ)在宿主變量中用于輸入或輸出的值。在預(yù)編譯期,每一個(gè)宿主變量會(huì)被賦予一個(gè)默認(rèn)的Oracle外部數(shù)據(jù)類型。數(shù)據(jù)類型同等化允許你重載默認(rèn)的同等化,并允許你控制Oracle輸入數(shù)據(jù)的解釋和輸出數(shù)據(jù)的格式化。同等化通過(guò)使用VAR表達(dá)式實(shí)現(xiàn)基于從變量到變量的轉(zhuǎn)換。語(yǔ)法是:EXEC SQL VAR? IS? [ () ];
舉例來(lái)說(shuō), 假設(shè)你想從emp表中查詢雇員名子,然后傳給一個(gè)需要C類型(以''結(jié)尾的)字符串的程序,你不需要顯式的用''來(lái)結(jié)束這個(gè)名子。如下面所示,簡(jiǎn)單地將宿主變量同等化為外部數(shù)據(jù)類型STRING:char emp_name[21];
EXEC SQL VAR emp_name IS STRING(21);
emp表中ename字段的長(zhǎng)是20字符(character),因此,需要分配21字符(character)以適應(yīng)''結(jié)束符。Oracle的外部數(shù)據(jù)類型STRING是為C類型字符串特別設(shè)計(jì)的接口。當(dāng)把ename字段值傳給emp_name時(shí),Oracle會(huì)自動(dòng)用' '結(jié)尾。也可以使用TYPE語(yǔ)句將用戶自定義數(shù)據(jù)類型同等化為Oracle外部數(shù)據(jù)類型。語(yǔ)法是:EXEC SQL TYPE? IS? [ () ] [REFERENCE];
可以聲明一個(gè)用戶自定義類型的指針,顯式的如指向標(biāo)量或結(jié)構(gòu)的指針,或隱式的如數(shù)組,然后在TYPE表達(dá)式中使用這個(gè)類型。這種情況下,你需要在表達(dá)式后使用REFERENCE子句,如下所示:typedef unsigned char *my_raw;
EXEC SQL TYPE my_raw IS VARRAW(4000) REFERENCE;
my_raw buffer;
/* ... */
buffer = malloc(4004);
這里,我們分配了比源類型長(zhǎng)(4000)更多的內(nèi)存,這是因?yàn)轭A(yù)編譯器要返回長(zhǎng)度,而且可能需要填充適當(dāng)?shù)拈L(zhǎng)度以滿足系統(tǒng)的對(duì)齊要求。
--------------------------------------------------------------------------------動(dòng)態(tài)SQL
嵌入SQL能夠滿足一個(gè)固定的應(yīng)用,但有時(shí)動(dòng)態(tài)產(chǎn)生完整的SQL語(yǔ)句也是很重要的。對(duì)于動(dòng)態(tài)SQL,語(yǔ)句存儲(chǔ)在字符串變量中,PREPARE把字符串轉(zhuǎn)換為SQL語(yǔ)句,然后用EXECUTE執(zhí)行這個(gè)語(yǔ)句。考慮下面的例子:char *s = "INSERT INTO emp VALUES(1234, 'jon', 3)";
EXEC SQL PREPARE q FROM :s;
EXEC SQL EXECUTE q;
PREPARE和EXECUTE可放到一個(gè)語(yǔ)句中,像這樣:char *s = "INSERT INTO emp VALUES(1234, 'jon', 3)";
EXEC SQL EXECUTE IMMEDIATE :s;
--------------------------------------------------------------------------------事務(wù)
Oracle Pro*C支持標(biāo)準(zhǔn)SQL定義的事務(wù)。一個(gè)事務(wù)是一組SQL語(yǔ)句集合,Oracle把它當(dāng)作單獨(dú)的單元運(yùn)行。一個(gè)事務(wù)從第一個(gè)SQL語(yǔ)句開(kāi)始,遇到"EXEC SQL COMMIT"(執(zhí)行當(dāng)前事務(wù)對(duì)數(shù)據(jù)庫(kù)的永久修改)或"EXEC SQL ROLLBACK"(取消從事務(wù)開(kāi)始到當(dāng)前位置對(duì)數(shù)據(jù)庫(kù)的任何修改)時(shí)結(jié)束事務(wù)。當(dāng)前事務(wù)由COMMIT或ROLLBACK語(yǔ)句結(jié)束后,下一條可執(zhí)行SQL語(yǔ)句將自動(dòng)開(kāi)始一個(gè)新事務(wù)。如果程序結(jié)束時(shí)沒(méi)有執(zhí)行EXEC SQL COMMIT,則對(duì)數(shù)據(jù)庫(kù)的所作的修改都將被忽略。
--------------------------------------------------------------------------------錯(cuò)誤處理
在每個(gè)可執(zhí)行的SQL表達(dá)式之后,可以在程序中檢查SQLCA顯式地或用WHENEVER語(yǔ)句隱式地得到執(zhí)行狀態(tài)信息。下面將詳細(xì)地介紹這兩種方法。
--------------------------------------------------------------------------------SQLCA
SQLCA(SQL Communications Area,SQL通訊區(qū))用于在程序中檢查錯(cuò)誤和狀態(tài)變化。每個(gè)可執(zhí)行SQL語(yǔ)句執(zhí)行后,Oracle 運(yùn)行時(shí)會(huì)在這個(gè)結(jié)構(gòu)中填入信息。如果要使用SQLCA,你要用#include包含進(jìn)sqlca.h頭文件。如果在很多地方包含了頭文件,你要使用#undef SQLCA來(lái)取消SQLCA的宏定義。sqlca.h中的相關(guān)程序塊如下:#ifndef SQLCA
#define SQLCA 1struct sqlca {
??? /* ub1 */ char sqlcaid[8];
??? /* b4 */ long sqlabc;
??? /* b4 */ long sqlcode;
??? struct {
??????? /* ub2 */ unsigned short sqlerrml;
??????? /* ub1 */ char sqlerrmc[70];
??? } sqlerrm;
??? /* ub1 */ char sqlerrp[8];
??? /* b4 */ long sqlerrd[6];
??? /* ub1 */ char sqlwarn[8];
??? /* ub1 */ char sqlext[8];
};
/* ... */
sqlca域有下列的意義:sqlcaid 該字符串域初始化為"SQLCA",以指明這是個(gè)SQL通訊區(qū)。?
sqlcabc 該整數(shù)域用byte標(biāo)識(shí)SQLCA結(jié)構(gòu)的長(zhǎng)度。?
sqlcode 這個(gè)整數(shù)域標(biāo)識(shí)最近執(zhí)行的SQL語(yǔ)句的狀態(tài)碼:0 沒(méi)有錯(cuò)誤。?
>0 語(yǔ)句執(zhí)行但捕獲異常。當(dāng)Oracle根據(jù)WHERE條件查找不到任何記錄,或SELECT INTO或FETCH影響記錄數(shù)為0時(shí)會(huì)發(fā)生這種情況。?
<0 由于一個(gè)錯(cuò)誤Oracle不能執(zhí)行SQL語(yǔ)句。當(dāng)這個(gè)錯(cuò)誤發(fā)生時(shí),多數(shù)情況下當(dāng)前的事務(wù)應(yīng)該回滾(rollback)。?
?
sqlerrm 這個(gè)內(nèi)嵌結(jié)構(gòu)包含兩個(gè)域:?
sqlerrml - 在sqlerrmc中保存的信息文本的長(zhǎng)。?
sqlerrmc - 最大到70個(gè)字符(character)的信息文本,與sqlcode中存儲(chǔ)的錯(cuò)誤碼相似。
sqlerrp 保留?
sqlerrd 這個(gè)二進(jìn)制×××數(shù)組包含6個(gè)元素:?
sqlerrd[0] - 保留?
sqlerrd[1] - 保留?
sqlerrd[2] - 最近被執(zhí)行的SQL語(yǔ)句影響的記錄行數(shù)。?
sqlerrd[3] - 保留?
sqlerrd[4] - 分析最近執(zhí)行語(yǔ)句出現(xiàn)錯(cuò)誤,錯(cuò)誤的開(kāi)始字符的偏移。?
sqlerrd[5] - 保留
sqlwarn 這個(gè)單字符數(shù)組包含8個(gè)元素,用于警告標(biāo)志。Oracle使用字符'W'設(shè)置一個(gè)標(biāo)記。sqlwarn[0] 當(dāng)其它標(biāo)記被設(shè)置時(shí)設(shè)置。?
sqlwarn[1] 當(dāng)輸出宿主變量中保存的是被截?cái)嗟淖侄沃禃r(shí)設(shè)置。?
sqlwarn[2] 當(dāng)計(jì)算SQL統(tǒng)計(jì)如AVG或SUM時(shí),如果一個(gè)NULL字段不能被使用時(shí)被設(shè)置。?
sqlwarn[3] 當(dāng)SELECT的字段數(shù)與INTO句中指定的宿主變量數(shù)不等時(shí)設(shè)置。?
sqlwarn[4] 當(dāng)沒(méi)有使用WHERE子句的UPDATE或DELETE語(yǔ)句處理了數(shù)據(jù)表中的每一行時(shí)設(shè)置。?
sqlwarn[5] 當(dāng)由于PL/SQL編譯錯(cuò)誤而導(dǎo)致procedure/function/package/package body創(chuàng)建命令失敗時(shí)設(shè)置。?
sqlwarn[6] 不再使用?
sqlwarn[7] 不再使用?
?
sqlext 保留SQLCA只能在sqlerrm域中存儲(chǔ)最大70字符長(zhǎng)的錯(cuò)誤信息。要得到更長(zhǎng)的(或嵌套的)全部錯(cuò)誤信息字符,可以使用sqlglm()函數(shù):void sqlglm(char *msg_buf, size_t *buf_size, size_t *msg_length);
msg_buf是Oracle存儲(chǔ)錯(cuò)誤信息的字符緩沖;buf_size指定msg_buf的長(zhǎng)(byte); Oracle在*msg_length中存放實(shí)際的錯(cuò)誤信息長(zhǎng)。Oracle錯(cuò)誤信息的最大長(zhǎng)度是512字節(jié)(byte)。
--------------------------------------------------------------------------------WHENEVER語(yǔ)句
這個(gè)表達(dá)式進(jìn)行自動(dòng)錯(cuò)誤檢查和處理。語(yǔ)法是:EXEC SQL WHENEVER? ;
Oracle自動(dòng)檢查的SQLCA,當(dāng)條件被檢測(cè)到時(shí),程序會(huì)自動(dòng)執(zhí)行可以是下列各項(xiàng):SQLWARNING - 由于Oracle返回一個(gè)警告而設(shè)置sqlwarn[0]?
SQLERROR - 由于Oracle返回一個(gè)錯(cuò)誤, sqlcode的值為負(fù)?
NOT FOUND - 由于Oracle按WHERE的條件沒(méi)有找到任何一條記錄,或SELECT INTO或FETCH返回0條記錄,而使sqlcode為正
可以為下列各項(xiàng):CONTINUE - 只要可能,程序會(huì)嘗試?yán)^續(xù)運(yùn)行之后的語(yǔ)句?
DO - 程序?qū)⒖刂茩?quán)交給一個(gè)錯(cuò)誤處理模塊?
GOTO - 程序跳轉(zhuǎn)到被標(biāo)示的語(yǔ)句?
STOP - 調(diào)用exit()結(jié)束程序,回滾未提交的操作
下面是WHENEVER語(yǔ)句的例子:EXEC SQL WHENEVER SQLWARNING DO print_warning_msg();
EXEC SQL WHENEVER NOT FOUND GOTO handle_empty;
下面是一個(gè)更詳細(xì)的例子:/* code to find student name given id */
/* ... */
for (;;)
{
??? printf("Give student id number : ");
??? scanf("%d", &id);
??? EXEC SQL WHENEVER NOT FOUND GOTO notfound;
??? EXEC SQL SELECT studentname INTO :st_name
???????????? FROM?? student
???????????? WHERE? studentid = :id;
??? printf("Name of student is %s. ", st_name);
??? continue;
notfound:
??? printf("No record exists for id %d! ", id);
}
/* ... */
注意WHENEVER表達(dá)式不遵從標(biāo)準(zhǔn)C的作用域規(guī)則,整個(gè)程序都是它的作用域。舉例來(lái)說(shuō),如果下面的語(yǔ)句在你程序中的什么地方(如在一個(gè)循環(huán)之前):EXEC SQL WHENEVER NOT FOUND DO break;?
這個(gè)文件在這行之后出現(xiàn)的所有SQL語(yǔ)句都會(huì)受其影響。當(dāng)不再需要WHENEVER 的來(lái)影響程序時(shí)(比如在你的循環(huán)之后),確保使用下面的語(yǔ)句取消它的使用。EXEC SQL WHENEVER NOT FOUND CONTINUE;
--------------------------------------------------------------------------------Demo程序
注意: 例程會(huì)創(chuàng)建、使用四個(gè)表:DEPT、EMP、PAY1和PAY2。注意你的數(shù)據(jù)庫(kù)中可能會(huì)存在相同名子的表!在leland系統(tǒng)的/afs/ir/class/cs145/code/proc下有很多例程。它們被命名為sample*.pc(C用戶)和cppdemo*.pc(C++用戶)。 ".pc"是Pro*C代碼的擴(kuò)展名。由于有幾個(gè)固定的步驟復(fù)制這些文件,所以不要手工復(fù)制它們。下面介紹如何下載和設(shè)置例程:確認(rèn)你已經(jīng)運(yùn)行了source /afs/ir/class/cs145/all.env?
在你的目錄下,運(yùn)行l(wèi)oad_samples , 是你想放置例程的地方(例:load_samples sally etaoinshrdlu cs145_samples )?
cd?
運(yùn)行make samples(C++用戶運(yùn)行make cppsamples)編譯所有的例程。
第2步將會(huì)建立樣品數(shù)據(jù)庫(kù),創(chuàng)建在指定的新目錄,然后把文件復(fù)制到目錄下。它會(huì)在例程中修改你的用戶名和密碼,所有你不必每次運(yùn)行例程時(shí)都要輸入用戶名和密碼。sample1 和cppdemo1也為用戶提供了輸入用戶名和密碼的接口,當(dāng)你想要學(xué)習(xí)如何使用的時(shí)候。如果在第2步輸入用戶名和密碼時(shí)產(chǎn)生了任何錯(cuò)誤,只要在你的目錄下運(yùn)行clean_sample & lt;sample_dir>,然后重做第2步到第4步。對(duì)于第4步,你可以單獨(dú)編譯每一個(gè)例程。比如單獨(dú)編譯sample1.pc。編譯過(guò)程實(shí)際上有兩句:proc iname=sample1.pc
把內(nèi)嵌SQL代碼轉(zhuǎn)換為相應(yīng)的庫(kù)調(diào)用,輸出sample1.c?
cc sample1.c
主成可執(zhí)行的sample1
編譯你自己的代碼,如foo.pc,只要修改Makefile的幾個(gè)變量:在SAMPLES變量中加入foo程序名,在SAMPLE_SRC變量中加入foo.pc源文件名。然后,寫(xiě)好foo.pc 后make foo。foo.pc被預(yù)編譯為foo.c,再編譯為可執(zhí)行的foo。C++用戶要把程序名和源文件名加入到CPPSAMPLE和CPPSAMPLE_SRC而不是SAMPLES和SAMPLE_SRC。例程運(yùn)行于下面的數(shù)據(jù)庫(kù)表上:CREATE TABLE DEPT
??? (DEPTNO??? NUMBER(2) NOT NULL,
???? DNAME???? VARCHAR2(14),
???? LOC?????? VARCHAR2(13));CREATE TABLE EMP
??? (EMPNO???? NUMBER(4) NOT NULL,
???? ENAME???? VARCHAR2(10),
???? JOB?????? VARCHAR2(9),
???? MGR?????? NUMBER(4),
???? HIREDATE? DATE,
???? SAL?????? NUMBER(7, 2),
???? COMM????? NUMBER(7, 2),
???? DEPTNO??? NUMBER(2));CREATE TABLE PAY1
??? (ENAME???? VARCHAR2(10),
???? SAL?????? NUMBER(7, 2));CREATE TABLE PAY2
??? (ENAME???? VARCHAR2(10),
???? SAL?????? NUMBER(7, 2));
當(dāng)在第2步運(yùn)行l(wèi)oad_samples的時(shí)候這些表就自動(dòng)創(chuàng)建好了。一些tuples(譯注:沒(méi)找到合適的詞,把原詞放這了)也插入了。你可以在程序運(yùn)行前查看這些表也可以任意操作這些表(如:插入、刪除或是更新tuples)。當(dāng)你運(yùn)行clean_sample時(shí),這些表自動(dòng)被刪除。注意:clean_sample也會(huì)清理整個(gè);;確保在運(yùn)行這個(gè)命令之前將你自己的文件轉(zhuǎn)移到其它的地方!你應(yīng)該在運(yùn)行它之前看一看源代碼,頭部的注釋描述了程序都做些什么。例如,sample1從一個(gè)雇員的EMPNO 得到他的名子和工資,從EMP表中得到的那個(gè)雇員的傭金。通過(guò)學(xué)習(xí)源程序你應(yīng)該可以學(xué)到下面的東西:如何從主機(jī)連接到Oracle?
如何在C/C++中嵌入SQL?
如何使用游標(biāo)?
如何使用宿主變量與數(shù)據(jù)庫(kù)通訊?
如何使用WHENEVER進(jìn)行不同的錯(cuò)誤處理動(dòng)作?
如何使用指示器變量檢測(cè)輸出中的空值
現(xiàn)在,你可以使用這些技術(shù)編寫(xiě)你自己的數(shù)據(jù)庫(kù)應(yīng)用程序了。And have fun!
--------------------------------------------------------------------------------C++用戶
要使用預(yù)編譯器生成合適的C++代碼,你需要注意下面的事項(xiàng):代碼被預(yù)編譯器展開(kāi)。要得到C++代碼,你需要在執(zhí)行proc時(shí)設(shè)置CODE=CPP選項(xiàng)。
解析能力。proc的PARSE選項(xiàng)可以是下面的值:
PARSE=NONE. C預(yù)處理指令只能在聲明節(jié)中被解析,所以所有的宿主變量需要在聲明節(jié)中聲明。
PARSE=PARTIAL. C預(yù)處理指令能被解析;然而,所有的宿主變量需要在聲明節(jié)中聲明。
PARSE=FULL. C預(yù)處理指令能被解析,而且宿主變量可以聲明在任何地方。當(dāng)CODE不為 CPP時(shí),這是默認(rèn)設(shè)置;但當(dāng)CODE=CPP時(shí),指定PARSE=FULL卻是個(gè)錯(cuò)誤。
所以,C++用戶必須指定PARSE=NONE或PARSE=PARTIAL,因此這也失去了在任意地方聲明宿主變量的自由。更有,宿主變量必須被包在一個(gè)聲明節(jié)中,如下:?
EXEC SQL BEGIN DECLARE SECTION;
??? // declarations...
EXEC SQL END DECLARE SECTION;
你需要使用這種方法去聲明所有的宿主和指示器變量。
文件擴(kuò)展名。你要指定設(shè)置CPP_SUFFIX=cc或CPP_SUFFIX=C。
頭文件定位。默認(rèn)情況下,proc像標(biāo)準(zhǔn)定位stdio.h文件一樣查找頭文件。然而C++有自己的頭文件,如iostream.h,被放置在別處。所以,你需要使用SYS_INCLUDE選項(xiàng)指定proc查找頭文件的路徑。--------------------------------------------------------------------------------Pro*C支持的嵌入SQL語(yǔ)句列表
聲明表達(dá)式?
EXEC SQL ARRAYLEN 在PL/SQL中使用宿主變量?
EXEC SQL BEGIN DECLARE SECTION?
EXEC SQL END DECLARE SECTION 聲明宿主變量?
EXEC SQL DECLARE 給Oracle對(duì)像命名?
EXEC SQL INCLUDE 從文件中復(fù)制?
EXEC SQL TYPE 同等化數(shù)據(jù)類型?
EXEC SQL VAR 同等化變量?
EXEC SQL WHENEVER 處理運(yùn)行時(shí)錯(cuò)誤?
執(zhí)行表達(dá)式?
EXEC SQL ALLOCATE 聲明、控制Oracle數(shù)據(jù)?
EXEC SQL ALTER?
EXEC SQL ANALYZE?
EXEC SQL AUDIT?
EXEC SQL COMMENT?
EXEC SQL CONNECT?
EXEC SQL CREATE?
EXEC SQL DROP?
EXEC SQL GRANT?
EXEC SQL NOAUDIT?
EXEC SQL RENAME?
EXEC SQL REVOKE?
EXEC SQL TRUNCATE?
EXEC SQL CLOSE?
EXEC SQL DELETE 排序、修改Oracle數(shù)據(jù)?
EXEC SQL EXPLAIN PLAN?
EXEC SQL FETCH?
EXEC SQL INSERT?
EXEC SQL LOCK TABLE?
EXEC SQL OPEN?
EXEC SQL SELECT?
EXEC SQL UPDATE?
EXEC SQL COMMIT 處理事務(wù)?
EXEC SQL ROLLBACK?
EXEC SQL SAVEPOINT?
EXEC SQL SET TRANSACTION?
EXEC SQL DESCRIBE 使用動(dòng)態(tài)SQL?
EXEC SQL EXECUTE?
EXEC SQL PREPARE?
EXEC SQL ALTER SESSION 控制會(huì)話?
EXEC SQL SET ROLE?
EXEC SQL EXECUTE?
END-EXEC 內(nèi)嵌PL/SQL塊
轉(zhuǎn)載于:https://blog.51cto.com/3633188/1184120
總結(jié)
以上是生活随笔為你收集整理的介绍Pro*c编程的经验的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 游戏代练人员恶意毁号,法院判其赔近 5
- 下一篇: 一步步构建大型网站架构(转)