本文來源于網頁設計愛好者web開發社區http://www.html.org.cn收集整理,歡迎訪問。一 pro*c 程序概述:
1.什么是pro*c程序
在oracle數據庫管理和系統中, 有三種訪問數據庫的方法;
(1) 用sql*plus, 它有sql命令以交互的應用程序訪問數據庫;
(2)用第四代語言應用開發工具開發的應用程序訪問數據庫,這些工具有sql*froms,ql*reportwriter,sql*menu等;
(3) 利用在第三代語言內嵌入的sql語言或oracle庫函數調用來訪問。
pro*c就屬于第三種開發工具之一, 它把過程化語言c和非過程化語言sql最完善地結合起來,
具有完備的過程處理能力,又能完成任何數據庫的處理品任務,使用戶可以通過編程完成各種類型的報表。在pro*c程序中可以嵌入sql語言,
利用這些sql語言可以完成動態地建立、修改和刪除數據庫中的表,也可以查詢、插入、修改和刪除數據庫表中的行, 還可以實現事務的提交和回滾。
在pro*c程序中還可以嵌入pl/sql塊, 以改進應用程序的性能, 特別是在網絡環境下,可以減少網絡傳輸和處理的總開銷。
2.pro*c的程序結構圖
通俗來說,pro*c程序實際是內嵌有sql語句或pl/sql塊的c程序, 因此它的組成很類似c程序。 但因為它內嵌有sql語句或pl/sql塊,
所以它還含有與之不同的成份。為了讓大家對pro*c有個感性的認識, 特將二者差別比較如下:
c的全程變量說明
c源程序 函數1:同函數k。
函數2:同函數k。
c的局部變量說明
函數k
可執行語句
應用程序首部 c的外部變量說明
外部說明段(oracle變量說明)
通訊區說明
pro*c源程序 函數1:同函數k。
函數2:同函數k。
c局部變量說明
程序體 內部說明部分 內部說明段
通訊區說明
函數k c的可執行語句
可執行語句 sql的可執行語句
或pl/sql塊
二.pro*c程序的組成結構
每一個pro*c程序都包括兩部分:(1)應用程序首部;(2)應用程序體
應用程序首部定義了oracle數據庫的有關變量,
為在c語言中操縱oracle數據庫做好了準備。應用程序體基本上由pro*c的sql語句調用組成。主要指查詢select、insert、update、delete等語句。
應用程序的組成結構如圖所示:
應用程序首部
描述部分
sql通信區
應用程序體
exec sql begin declare section
(sql變量的定義)
exec sql end declare section;
exec sql include sqlla;
exec sql connect:< 用戶名>
identified by: < 口令 >
sql 語句及游標的使用
1. 應用程序首部
應用程序的首部就是pro*c的開始部分。它包括以下三部分:
l c變量描述部分;
l sql變量描述部分(declare部分);
l sql通信區。
(1) .declare部分(描述部分)
描述部分說明程序的sql變量, 定義部分以exec sql begin declare section ;開始和以 exec sql end declare
section ;結束的。它可以出現在程序的主部,也可出現在局部
l sql變量的說明和使用
在說明段能為sql變量指定的數據類型如表所示:
數據類型描述
char
char(n)
int
short
long
float
double
varchar單字符
n個字符數組
整數
短整數
單精度浮點數
雙精度浮點數
變長字符串
這些數據類型實際上就是c語言的數據類型, 其中varchar中視為c數據類型的擴充。這在以后會談到。
sql變量的使用應注意以下幾點:
l 必須在描述部分明確定義
l 必須使用與其定義相同的大小寫格式
l 在sql語句中使用時,必須在其之前加一個“:”(冒號),但在c語句中引用時不需加冒號。
l 不能是sql命令中的保留字。
l 可以帶指示變量。
例如:exec sql begin declare sections;
varchar programe[30];
int porgsal, pempno;
exec sql end declare section;
exec sql select ename , sal
into: programe, : progsal
from emp
where empno = : pempno;
(2). 指示器變量的說明和引用
指示變量實際上也是一類sql變量,它被用來管理與其相關聯的宿主變量(即在sql語句中充
當輸入或輸出的變量)。每一個宿主變量都可定義一個指示器變量,主要用于處理空值(null)
指示器變量的說明基本同一般sql變量一樣, 但必須定義成2字節的整型,如short、int。在sql語句中引用時,
其前也應加“:”(冒號),而且必須附在其相關聯的宿主變量之后,在c語句中,可獨立使用。當指示器變量為-1時,表示空值。例如:
exec sql begin declare section ;
int dept- number;
short ind – num;
char emp –name;
exec sql end declare section ;
scanf(“90d %s”, & dept- number , dept – name );
if (dept – number ==0)
ind – num = -1;
else
ind – num = 0;
exec sql insert into dept (deptno, dname)
values(:dept – number : ind- num , :dept – name);
其中ind – num是dept – number 的指示器變量。當輸入的dept – number 值是0時, 則向dept 表的deptno列插入空值。
(3).指針sql變量的說明和使用
指針sql變量在引用前也必須在declare
部分先說明。其說明格式同c語言。在sql語句中引用時,指針名字前要加前綴“:”(冒號)而不加“*”(星號)。在c語句中用法如同c語言的指針變量。
(4).數組sql變更的說明和引用
在sql語句中引用數組時,只需寫數組名(名字前加冒號), 不需寫下標,在c語句中用法如同c語言的數組變量。
使用數組可大大降低網絡傳輸開銷。如要向一表插入100行數據,如果沒有數組,就要重復100次, 而引用后,只須執行一次insert語句、便可一次性插入。例如:
exec sql begin declare section;
int emp_number[100];
char emp_name[100][15];
float salary[100],commission[100];
int dept_number;
exec sql end declare section;
….
exec sql select empno,ename,sal,comm
into :emp_number,:emp_name,:salary,:commission
from emp
where deptno=:dept_number;
在使用數組時,應注意以下幾點;
l 不支持指針數組
l 只支持一維數組, 而 emp-name [100][15]視為一維字符串
l 數組最大維數為32767
l 在一條sql語句中引用多個數組時,這些數組維數應相同
l 在values , set, into 或where子名中, 不允許把簡單sql變量與數組sql變量混用
l 不能在delare部分初始化數組
例如:下面的引用是非法的
exec sql begin declare section;
int dept – num [3] = {10,20,30};
exec sql end declare section ;
exec sql select empno, ename , sal
into : emp – num [ i ], : emp – name [ i ], : salarg [ i ]
from emp
(5) 偽類型varchar的說明和引用
varchar變量在引用之前也必須在說明段說明, 說明時必須指出串的最大
長度,如:
exec sql begin declare section;
int book – number;
varchar book – name [ 50 ];
exec sql end declare section ;
在預編繹時, book – name 被翻譯成c語言中的一個結構變量;
struct { unsigned short len ;
unsigned chart arr [ 20 ] ;
} boo – name
由此看出, varchar變量實際上是含長度成員和數組成員的結構變量。在sql語句中引用時,應引用以冒號為前綴的結構名, 而不加下標,在c語句 中引用結構成員。
varchar變量在作輸出變量時,由oracle自動設置, 在作為輸入變量時,程序應先把字符串存入數組成員中,
其長度存入長度成員中,然后再在sql語句中引用。例如:
main( )
{ .......
scanf(“90s, 90d’, book – name .arr, & book – number );
book – name .len = strlen (book – name .arr);
exec sql update book
set bname = : book – name ;
bdesc = : book – number ;
}
(6) sql通信區
sql 通信區是用下列語句描述的:
exec sql include sqlca;
此部分提供了用戶運行程序的成敗記錄和錯誤處理。
sqlca的組成
sqlca是一個結構類型的變量,它是oracle 和應用程序的一個接口。在執行 pro*c程序時, oracle
把每一個嵌入sql語句執行的狀態信息存入sqlca中, 根據這些信息,可判斷sql語句的執行是否成功,處理的行數,錯誤信息等,其組成如表所示:
struct sqlca
{ char sqlcaid [ 8 ] ; ----à標識通訊區
long sqlabc; ---à 通訊區的長度
long sqlcode; ---à保留最近執行的sql語句的狀態碼
struct { unsigned short sqlerrml; -----à信息文本長度
}sqlerrm;
char sqlerrp [ 8 ];
long sqlerrd [ 6 ];
char sqlwarn [ 8 ];
char sqlext [ 8 ];
}
struct sqlca sqlca;
其中, sqlcode在程序中最常用到,它保留了最近執行的sql語句的狀態碼。程序員根據這些狀態碼做出相應的處理。這些狀態碼值如下:
0: 表示該sql語句被正確執行,沒有發生錯誤和例外。
>0:oracle執行了該語句,但遇到一個例外(如沒找到任何數據)。
<0:表示由于數據庫、系統、網絡或應用程序的錯誤,oracle未執行該sql語句。
當出現此類錯誤時,當前事務一般應回滾。
2.應用程序體
在pro*c程序中, 能把sql語句和c語句自由地混合書寫,并能在sql語句中使用sql變量,嵌入式sql語句的書寫文法是:
l 以關鍵字exec sql開始
l 以c語言的語句終結符(分號)終結
sql語句的作用主要用于同數據庫打交道。c語言程序用于控制,輸入,輸出和數據處理等。
(1) 連接到oracle數據庫
在對數據庫存取之前,必須先把程序與oracle數據庫連接起來。即登錄到oracle上。所連接命令應該是應用程序的第一個可執行命令。連接命令格式如下:
exec sql connect:< 用戶名 > identified by : < 口令 >
或exec sql connect: < 用戶名 > / < 口令 >
在使用上述兩種格式進行登入時, 應當首先在說明段定義包含用戶名和口令的
sql 變量,并在執行connect之前設置它們,否則會造成登錄失敗。例如:
exec sql begin declare section ;
varchar usename [20];
varchar password[20];
exec sql end declare
..........
strcpy ( usename.arr, “csott’);
usename.len = strlen (username.arr);
strcpy (password.arr , “tiger’);
password .len = strlen( password .arr);
exec sql whenever sqlerror goto sqlerr;
exec sql connect :username indntified by : password;
注意: 不能把用戶名和口令直接編寫到connect語句中,或者把用引號(’)括起來的字母串在connect 語句中, 如下面的語句是無效的。
exec sql connect scott inentified by tiger;
exec sql connect ‘scott’ identified by ‘tiger’;
(2). 插入、更新和刪除
在講述sql語言時已詳細講過, 這里就不舉例說明了。
(3). 數據庫查詢及游標的使用
在pro*c中, 查詢可分為兩種類型:
l 返回單行或定行數的查詢;
l 返回多行的查詢.此種查詢要求使用游標來控制每一行或每一組(主變量用數組).
1) 返回單行或定行數的查詢
在pro*c中的查詢sql select語句由以下幾個子句組成:
select
into
from
where
connect by
union
intersect
minus
group by
having
order by
其中where子句中的查詢條件可以是一個屬性或多個屬性的集合,在執行是賦值的主變量也可放在where子句中.where子句中所用的主變量稱為輸入主變量。如:
select empno, job, sal
into:pname, :pjob, :psal
from emp
where empno=:pempno;
若沒有找到限定的行, 則sqlca.sqlcode返回”+1403”, 表明”沒有找到”。
into從句中的主變量叫輸出主變量,它提供了查詢時所需要的信息。
在任何項送給主變量之前,都要求oracle把這些項轉換成主變量的數據類型。對于數字是通過截斷來完成的(如:9.23轉換為9)。
如果已確定查詢只返回一行,那么就不必使用游標,只給select語句增加一個into子句即可。在語義上into語句在from之前的查詢中有多少個選擇項就有多少個輸出主變量。若在select項中表達式的數目不等于into子句中主變量的數目,就把sqlca.sqlwarn[3]置為”w”。
2)多行查詢及游標的使用
如果查詢返回多行或不知道返回多少行,使用帶有oracle游標(cursor)的select語句。
游標是oracle和pro*c存放查詢結果的工作區域。一個游標(已命名的)與一條select語句相關聯。操作游標有由4條命令:(1)declare
cursor;(2)open cursor;(3)fetch;(4)close cursor。
a. 定義游標
一個游標必須首先定義, 才能使用它。語法為:
exec sql declare 〈游標名〉corsor for
select 〈列〉
from 〈表〉
例如:
exec sql declare csor, cursor for
select ename , job, sal
from emp
where deptno=:deptno;
當賦給一個與查詢相關聯的游標cursor之后, 當select查詢emp時可從數據庫中返回多行,這些行就是cursor的一個活動區域。
注意:
1) 定義游標必須在對游標操作之前完成;
2) pro*c不能引用沒有定義的游標;
3) 游標定義后,其作用范圍是整個程序。所以對一個程序來講, 同時定義兩個相同的游標是錯誤的。
b. 打開游標
打開游標的open語句主要用來輸入主變量的內容,這些主要是where中使用的主變量。打開游標的語句是:exec sql open 〈游標名〉
當打開游標后,可以從相關的查詢中取出多于一行的結果。所有滿足查詢標準的行組成一集合,叫做“游標活動集”。通過取操作,活動集中的每一行或每一組是一個一個返回的,查詢完成后,
游標就可關閉了。如圖所示:
定義游標:declare
開始查詢:select
打開游標:open
從活動集取數據:fetch
查詢完成
關閉游標:close
注意:1)游標處于活動集的第一行前面;
2)若改變了輸入主變量就必須重新打開游標。
c. 取數據
從活動集中取出一行或一組把結果送到輸出主變量中的過程叫取數據。輸出主變量的定義在取數據語句中。取數據的語句如下:
exec sql fetch〈游標名〉into:主變量1,主變量2,……
fetch的工作過程如圖所示:
查詢結果
游標
fetch
查詢結果
在游標打開后
輸出至當前
……
如圖所示的查詢結果指滿足查詢條件的查詢結果。使用fetch應注意以下幾點:
l 游標必須先定義再打開。
l 只有在游標打開之后才能取數據,即執行fetch語句。
l
fetch語句每執行一次,從當前行或當前組取數據一次,下一行或下一組向上移一次。游標每次所指的行或組都為當前行或當前組,而fetch每次都是取游標所指定的行或組的數據。
l 當游標活動集空之后,orcle返回一個sqlca。sqlca(=1403)。
l 若希望此游標再操作, 必須先關閉再打開它。
l 在c程序中可以開辟一個內存空間,來存放操作結果,這樣就能利用開辟的空間來靈活操縱查詢的結果。
d.關閉游標
取完活動集中所有行后,必須關閉游標,以釋放與該游標有關的資源。
關閉游標的格式為:
exec sql close 游標名;
例如:
exec sql close c1;
oracle v5.0版支持sql格式“current of cursor”。這條語句將指向一個游標中最新取出的行,
以用于修改和刪除操作。該語句必須有取操作之后使用,它等同存儲一個rowid,并使用它。
(4).舉例
exec sql declare salespeople cursor for
select ssno, name, salary
from employee
where dname=‘sales’;
exec sql open salespeople;
exec sql fetch salespeople
into :ss,:name,:sal;
exec sql close salespeople;
(5)sql嵌套的方法及應用
嵌入sql與交互式sql在形式上有如下差別:
1) 在sql語句前增加前綴“exec sql”, 這一小小的差別其目的是在于預編譯時容易識別出來,
以便把每一條sql作為一條高級語言來處理。
2) 每一sql語句分為說明性語句和可執行語句兩大類。可執行語句又分為數據定義、數據控制、數據操縱、數據檢索四大類。
可執行性sql語句寫在高級語言的可執行處;說明性sql語句寫在高級語言的說明性的地方。
例如:在pro*c程序中建立一個名為book的表結構,過程如下:
#include〈stdio.h〉
exec sql begin declare section;
varchar uid[20], pwd[20];
exec sql end declare section;
exec sql include sqlca;
main()
{
/*login database*/
strcpy(uid.arr,’wu’);
uid.len=strlen(uid,arr);
strcpy(pwd.arr,’wu’);
pwd.len=strlen(pwd.arr);
exec sql connect:uid identifeed by:pwd;
exec sql create table book
( acqnum number, copies number , price number);
exec sql commit work release;
exit;
pro*c可非常簡便靈活地訪問orcle數據庫中的數據,同時又具有c語言高速的特點,因而可完成一些oracle產品不能完成的任務,例如以下一個固定的特殊格式輸出結果。
sql嵌套源程序示例
#unclude
typedef char asciz[20];
exec sql begin declare section;
exec sql type asciz is string (20) reference;
asciz username;
asciz password;
asciz emp_name(5);
int emp_number(5a);
float salary[5];
exec sql end declare section;
exec sql include sqlca;
void print_rows();
void sqlerror();
main()
{
int num_ret;
strcpy(username,”scott’);
strcpy(password, “tyger”);
exec sql whenever sqlerror do sqlerror();
exec sql connect:username identified by:password;
print (“/nconnected to oracle as user:%s/n”, username);
exec sql declare c1 cursor for
select empno , ename , sal from emp;
exec sql open c1;
num_ret = 0;
for(;;)
{
exec sql whenever not found do break;
exec sql fetch c1 into : emp_number , :emp_name , :salary;
print_rows (sqlca.sqlerrd[2] – num_ret);
num_ret=sqlca.sqlerrd[2];
}
if ((sqlca.sqlerrd[2] – num_ret)>0);
print _rows(sqlca.sqlerrd[2] –num_ret);
exec sql close c1;
printf(“/have a good day./n”);
exec sql commit work release;
}
void print_rows(n);
int n;
{
int i;
printf(“/nnumber employee salary/n”);
printf(“------------------------------/n”);
for (i=0;i printf(“% - 9d%- 8s%9.2f/n”,emp-number[i], emp---name[i],salary[i];
}
void sqlerror()
{
exec sql whenever sqlerror continue;
printf(“/noracle error detected:/n”);
printf(‘/n%.70s/n”, sqlca.sqlerrm.sqlerrmc);
exec sql rollback work release;
exit(1);
}
(6) 錯誤檢測和恢復
在使用sql語句和pro*c對數據庫進行操作時,常常有字段空值,無條件刪除,無行返回,數據溢出和截斷等現象發生,這種現象可以用sqlca和指示器變量來檢測。
1 sqlca的結構
在pro*c程序中sqlca結構如下:
struct sqlca{
char sqlcaid[8];
long sqlabc;
long sqlcode;
struct{
unsigned sqlerrm1;
char sqlerrmc[10];
}sqlerrm;
char sqlerrp[8];
long sqlerrd[6];
char sqlwarn[8];
char sqlext[8];
}
其中:
1) sqlca.sqlerrm.sqlerrmc:帶有sqlca。sqlcode的錯誤正文。
2) sqlca.sqlerrd:當前oracle的狀態,只有sqlca.sqlerrd[2]有意義,表示dml語句處理的行數。
3) sqlca.sqlwarn:提供可能遇到的條件信息。
在每執行一個sql語句后,oracle就把返回結果放入sqlca中,但說明語句除外。
用sqlca可以查看sql語句的執行結果。往往有三種結果:
=0:執行成功;
sqlca.sqlcode= >0:執行成功的狀態值;
<0:失敗,不允許繼續執行。
2 指示器變量
指示器變量有時也稱指示變量.指示變量與一個主變量相關聯,指出主變量的返回情況.
=0:返回值不為空, 未被截斷,值放在主變量中;
返回值= >0:返回值為空, 忽略主變量的值;
<0:主變量長度不夠就被截斷。
使用指示變量要注意:
l 在where子句中不能用指示變量。用null屬性來測試空值。
例如下列子句:
select…
from…
where ename is null;
是正確的,而
where ename=:peme:peme1
是錯誤的。
l 指示變量在插入空值之前為—1
l 可輸出空值。
3 whenever語句
whenever是說明語句,不返回sqlcode, 只是根據sqlca中的返回碼指定相關的措施。格式為
exec sql whenever [sqlerror|sqlwarning|notforund]
[stop|continue|goto<標號>];
其中
(1)[stop|continue|got<標號>]的缺省值為continue。
(2)sqlerror:sqlca.sqlcode<0;
(3)sqlwarnign:sqlca.sqlwarn[0]=“w”;
(4)notfound:sqlca.sqlcode=1403;
下面給出一段程序來說明whenever的用法:
exec sql begin deelare section;
varchar uid[20];
varchar pasw[20];
……
exec sql end declare section;
exec sql include sqlca;
main()
{
……
exec sql whenever sqlerror goto err;
exec sql connect:uid/:pwd;
……
exec sql declare csor1 cursor for
select 〈字段〉
form〈表〉
exec sql open csor1;
sql
……
exec sql whenever not found goto good;
for(;;)
exec sql fetch csor, into……
good:
……
printf(“/n查詢結束/n”);
exec sql close c1;
exec sql whenever sqlerror continue.
exec sql commit work release:
exit();
printf(“/n%70s|n”, sqlca.sqlerrm.sqlerrmc);
exec sql rollback work release:
exit(1);
}
(7) 動態定義語句
sql語句分動態定義語句和靜態定義語句兩種:
(1) 靜態定義語句:sql語句事先編入pro*c中,在經過預編譯器編譯之后形成目標程序*。boj,然后執行目標程序預即可。
(2) 動態定義語句:有些語句不能事先嵌入到pro*c程序中,要根據程序運行情況,用戶自己從輸入設備上(如終端上)實時輸入即將執行的sql語句。
動態定義語句有:
l execute immediate;
l prepare 與execute;
l prepare與fetch 和 open ;
l bind與define descriptor。
1. execute immediate語句
此語句表示立即執行, 并且只向sqlca返回執行結果,無其它信息。例如:
exec sql begin declare section;
varchar abcd[89];
varchar deay[20];
exec sql end declare section;
/** 輸出字符串到abcd **/
exec sql execute immediate :abcd;
注意:
1) execute immediate只能運行帶一個參數的動態語句。其中,abcd是參數,不是關鍵字。
2) execute immediate使用的先決條件是:sql語句不能包含主變量;sql語句不能是查詢語句。
3) 可用任何主變量作為execute immediate的參數;也可用字符串作為主變量。
2. prepare與execute語句
此語句表示“預編譯/執行”。此語句能夠預編譯一次而執行多次。語法為:
exec sql prepare 〈語句名〉from:主變量;
exec sql execute〈語句名〉[using:替換主變量];
prepare語句做兩件事:
(1) 預編譯sql語句;
(2) 給出sql語句的語句名。
注意:
l sql語句不能是查詢語句;
l prepare和execute可包含主變量;
l prepare不能多次執行。
例如:
#define username “scott”
#define password “tiger”
#include 
exec sql include sqlca;
exec sql begin declare section;
char * username=username;
char * password=password;
varchar sqlstmt[80];
int emp_number;
varchar emp_name[15];
varchar job[50];
exec sql end declare section;
main()
{
exec sql whenever sqlerror goto :sqlerror;
exec sql connect :username identified by :password;
sqlstmt.len=sprintf(sqlstmt.arr,”insert into emp (empno,ename,job,sal)
values(:v1,:v2,:v3,:v4)”);
puts(sqlstmt.arr);
exec sql prepare s from :sqlstmt;
for(;;)
{
printf(“/nenter employee number:”);
scanf(“%d”,&emp_number);
if (emp_number==0) break;
printf(“/nenter employee name:”);
scanf(“%s”,&emp_name.arr);
emp_name.len=strlen(emp_name.arr);
printf(“/nenter employee job:”);
scanf(“%s”,job.arr);
job.len=strlen(job.arr);
printf(“/nenter employee salary:”);
scanf(“%f”,&salary);
}
exec sql execute s using :emp_number,:emp_name,:job,:salary;
}
3. fetch語句和open語句
fetch語句和open語句這組動態語句是對游標進行操作的,其執行過程如下:
prepare〈語句名〉from 〈主變量字符串〉;
declare〈游標名〉for〈語句名〉;
open 〈游標名〉[using:替換變量1[,:替換變量變…]]
fetch〈游標名〉into: 主變量1[,:主變量2…]
close〈游標名〉
注意:
l sql語句允許使用查詢語句;
l select子句中的列名不能動態改變,只能預置;
l where和order by 子句可以動態改變條件。
一、 pro*c的編譯和運行
1.
先用oracle預編譯器proc對pro*c程序進行預處理,該編譯器將源程序中嵌入的sql語言翻譯成c語言,產生一個c語言編譯器能直接編譯的文件。生成文件的擴展名為
.c
2. 用c語言編譯器cc 對擴展名為 .c的文件編譯,產生目標碼文件,其擴展名為 .o
3. 使用make命令,連接目標碼文件,生成可運行文件
例如: 對上面的example.pc進行編譯運行
proc iname=example.pc
cc example.c
make exe=example objs=”example.o”
example