最近帮做的一个数据库实验,过程中觉得网上 Pro*C 的资源和实例不多,于是想记录一下。
简单说下 Pro*C 程序简单原理:编写一个后缀名为 .pc 的源代码,内容是正常的 C 代码嵌入 Pro*C 语句,然后预编译成后缀名为 .c 的文件,再编译为 exe 可执行文件。
如Linux下执行命令:
precompiledimensxcn1:pgirard> chmod 700 precompile
dimensxcn1:pgirard> chmod 700 compile
dimensxcn1:pgirard> ./precompile
Pro*C/C++: Release 8.1.7.0.0 - Production on Sat Mar 8 17:48:12 2008
(c) Copyright 2000 Oracle Corporation. All rights reserved.
System default option values taken from: /disk/disk1/oracle/OraHome1/precomp/adg
dimensxcn1:pgirard> ./compile
dimensxcn1:pgirard> ./user_tec
预编译语句:
proc INAME=user_tec.pc CODE=ANSI_C SQLCHECK=semantics mode=oracle userid=user/password char_map=charz
编译语句:
gcc user_tec.c -o user_tec -include /$ORACLE_HOME/precomp/public/sqlca.h -lclntsh -B$ORACLE_HOME/lib/ -B$ORACLE_HOME/lib
值得注意的是,通过 C 语言变量接收 SELECT 语句返回的结果有两种形式,一种是刚才说到的 INTO :[已经声明好的C变量],但这种方法有局限性,只有在结果集为一行时有效,若结果集为多行则会报错,这是需要通过一个 cursor (游标)对结果集进行遍历,如 user_tec.pc 中的函数。
话不多说,对于 Pro*C 略有掌握的可以直接看代码,看不懂的可以往下拉看下题目大意。
采购部门管理员界面:
/*
user_pds.pc
Pro*C Programe for Pruchasing Department Supervisor
By Mr.Zhangweijian
date:June 6, 2017
*/
#include
#include
void sql_error();
void do_connect();
int print_menu();
void modresp();//给定一个part_id,修改其关联的agent
void quant();//给定一个agent号和一个日期,输出这个采购商所关联的,订单日期在这个日期以前的订单数量和订单总价值
int main()
{
EXEC SQL WHENEVER SQLERROR do sql_error("Error at connect");
do_connect();
while(1)
{
switch(print_menu())
{
case 1: modresp(); break;
case 2: quant(); break;
case 3: puts("\nAu revoir Sayonara Bye bye,Ni Hao"); exit(0);
default: puts("\n====>Enter a digit from the menu please?"); break;
}
}
EXEC SQL COMMIT WORK RELEASE;
exit(0);
}
void sql_error(char *msg)
{
char ora_msg[512];
int buf_len,msg_len;
EXEC SQL WHENEVER SQLERROR continue;
printf("\n%s\n",msg);
buf_len=sizeof(ora_msg);
sqlglm(ora_msg, &buf_len, &msg_len);
printf("\n%.*s\n",msg_len, ora_msg);
EXEC SQL ROLLBACK RELEASE;
exit(1);
}
void do_connect()
{
char *uid = "ora00067/AbB7dP";
EXEC SQL CONNECT :uid;
printf("Connected to Oracle schema\n");
}
int print_menu()
{
int choice;
printf("\t user_pds");
printf("\n\tChoose a transaction by entering a number\n");
printf("\t***********************************\n");
printf("\t(1)MODRESPON\n");
printf("\t(2)QUANT\n");
printf("\t(3)QUIT\n");
printf("Enter your choice?");
scanf("%d", &choice);
return choice;
}
/* ****************************************************************************************************
* Function to change the responsibility of a given part(part_id) from a agent to another agent
* ****************************************************************************************************
*/
void modresp()
{
int id,num, tstcode;
for(;;)
{
printf("Enter the part id to change (0 to quit)?");
scanf("%d", id);
if(id==0)
{
printf("End of this transaction\n");
return;
}
printf("Part number: %d\n", id);
printf("Enter the emp_num to change(0 to quit)?");
scanf("%d", num);
if(num==0)
{
printf("End of this transaction\n");
return;
}
printf("Part number: %d\n", num);
EXEC SQL EXECUTE
DECLARE
procedure mod_agent(id IN integer, num IN integer, stat OUT integer) is
BEGIN
stat := 1;
update responsible set emp_number=num where part_number=id;
if SQL%NOTFOUND then stat:=0;
end if;
END;
BEGIN
mod_agent(:id, :num, :tstcode);
END;
END-EXEC;
if(tstcode==0)
printf("Record not found\n");
else
printf("Modification done\n");
}
return;
}
/* ****************************************************************************************************
* Function to Display the number of purchase orders done by a given agent (emp_num)
* and the total value of these purchase orders since a given date
* ****************************************************************************************************
*/
void quant()
{
char des1[16];
char des2[16];
char date[10];
int my_empnum, none=1;
char my_podate[16];
for(;;)
{
printf("Number of the Agent(0 to quit)?");
scanf("%d", &my_empnum);
if(my_empnum == 0)
{
EXEC SQL COMMIT;
printf("End of this transaction\n");
break;
}
printf("Agent Number: %d\n", my_empnum);
printf("Date of po_date(yyyyMMdd, 0 to quit)?");
scanf("%s", my_podate);
if(strcmp(my_podate,"0")==0)
{
EXEC SQL COMMIT;
printf("End of this transaction\n");
break;
}
printf("Date: %s\n", my_podate);
EXEC SQL EXECUTE
BEGIN
SELECT count(po_number) INTO :des1
FROM pa_task WHERE emp_num=:my_empnum;
EXCEPTION
WHEN NO_DATA_FOUND THEN
:none:=0;
END;
END-EXEC;
if(none==0)
{
printf("Record not found\n");
none=1;
}
else
{
EXEC SQL EXECUTE
BEGIN
SELECT sum(purchase_order.total) INTO :des2
FROM pa_task,purchase_order WHERE pa_task.emp_num=:my_empnum and purchase_order.po_number=pa_task.po_number and purchase_order.po_date>:my_podate;
EXCEPTION
WHEN NO_DATA_FOUND THEN
:none:=0;
END;
END-EXEC;
if(none==0)
{
printf("Record not found\n");
none=1;
}
else
{
printf("**********Result**********\n");
printf(" count(po_number)\n");
printf("-----------------\n");
printf("\t%s\n", des1);
printf("sum(purchase_order.total)\n");
printf("------------------------\n");
printf("\t%s\n", des2);
}
}
EXEC SQL COMMIT;
}
return;
}
技术人员界面:
/*
user_tec.pc
Pro*C Programe for Technician
By Mr.Zhangweijian
date:June 6, 2017
*/
#include
#include
void sql_error();
void do_connect();
int print_menu();
void lispart();//给定一个part_id,显示这个part的具体信息
void explosion();//给定一个part_id,显示这个part相关联的component
void implosion();//给定一个componentid,显示这个component相关联的part
int main()
{
EXEC SQL WHENEVER SQLERROR do sql_error("Error at connect");
do_connect();
while(1)
{
switch(print_menu())
{
case 1: lispart(); break;
case 2: explosion(); break;
case 3: implosion(); break;
case 4: puts("\nAu revoir Sayonara Bye bye,Ni Hao"); exit(0);
default: puts("\n====>Enter a digit from the menu please?"); break;
}
}
EXEC SQL COMMIT WORK RELEASE;
exit(0);
}
int print_menu()
{
int choice;
printf("\t user_tec");
printf("\n\tChoose a transaction by entering a number\n");
printf("\t***********************************\n");
printf("\t(1)LISPART\n");
printf("\t(2)EXPLOSION\n");
printf("\t(3)IMPLOSION\n");
printf("\t(4)QUIT\n");
printf("Enter your choice?");
scanf("%d", &choice);
return choice;
}
/* ******************************************************************************************
* Function to display the contents of a given part
* ******************************************************************************************
*/
void lispart()
{
int des1;
char des2[16];
char des3[16];
int des4;
int des5;
int des6;
int des7;
int my_partid, none=1;
for(;;)
{
printf("Number of the part(0 to quit)?");
scanf("%d", &my_partid);
if(my_partid == 0)
{
EXEC SQL COMMIT;
printf("End of this transaction\n");
break;
}
printf("Part Number: %d\n", my_partid);
EXEC SQL DECLARE c1 CURSOR FOR
SELECT part_id,part_name,unit,unit_price,stock_qty,order_qty,min_qty
FROM part WHERE part_id = :my_partid;
EXEC SQL OPEN c1;
EXEC SQL WHENEVER NOT FOUND DO break;
while(1)
{
EXEC SQL FETCH c1 INTO :des1, :des2, :des3, :des4, :des5 ,:des6, des7;
printf("**********Result**********\n");
printf(" part_id part_name unit unit_price stock_qty order_qty min_qty\n");
printf("---------- ------------ ------- ------------ ------------ ------------- --------\n");
printf("\t%d\t%s\t%s\t%d\t%d\t%d\t%d\n", des1, des2, des3, des4, des5, des6, des7);
}
EXEC SQL CLOSE c1;
EXEC SQL COMMIT;
}
return;
}
/* ******************************************************************************************
* Function to display all components of a given part(part_id)
* ******************************************************************************************
*/
void explosion()
{
int des1;
char des2[16];
int des3;
int my_partid, none=1;
for(;;)
{
printf("Number of the part(0 to quit)?");
scanf("%d", &my_partid);
if(my_partid == 0)
{
EXEC SQL COMMIT;
printf("End of this transaction\n");
break;
}
printf("Part Number: %d\n", my_partid);
EXEC SQL DECLARE c1 CURSOR FOR
SELECT part_id,part_name,componentid
FROM part_tec,comp_tec WHERE comp_tec.partid = :my_partid AND comp_tec.partid=part_tec.part_id;
EXEC SQL OPEN c1;
EXEC SQL WHENEVER NOT FOUND DO break;
while(1)
{
EXEC SQL FETCH c1 INTO :des1, :des2, :des3;
printf("**********Result**********\n");
printf(" part_id part_name componentid\n");
printf("---------- ------------ ---------------\n");
printf("\t%d\t%s\t%d\n", des1, des2, des3);
}
EXEC SQL CLOSE c1;
EXEC SQL COMMIT;
}
return;
}
/* ******************************************************************************************
* Function to display all parts where a given part(part_id) is a component
* ******************************************************************************************
*/
void implosion()
{
char des1[16];
char des2[16];
char des3[16];
int my_partid, none=1;
for(;;)
{
printf("Number of the part(0 to quit)?");
scanf("%d", &my_partid);
if(my_partid == 0)
{
EXEC SQL COMMIT;
printf("End of this transaction\n");
break;
}
printf("Part Number: %d\n", my_partid);
EXEC SQL DECLARE c1 CURSOR FOR
SELECT componentid,part_id,part_name
FROM part_tec,comp_tec WHERE comp_tec.componentid = :my_partid AND comp_tec.partid=part_tec.part_id;
EXEC SQL OPEN c1;
EXEC SQL WHENEVER NOT FOUND DO break;
while(1)
{
EXEC SQL FETCH c1 INTO :des1, :des2, :des3;
printf("**********Result**********\n");
printf(" componentid part_id part_name\n");
printf("------------ ------------- ---------------\n");
printf("\t%s\t%s\t%s\n", des1, des2, des3);
}
EXEC SQL CLOSE c1;
EXEC SQL COMMIT;
}
return;
}
题目大意:
用 ProC 写 5 个用户程序,这 5 个用户程序分别有不同权限,可以对数据库(Linux下的MySQL)进行不同操作。5个角色有技术人员、采购商、仓库管理员等。
然后可以根据提示进行操作:
在任何输入的时候输入0则为退出。
数据库具体的几个表结构如下:
建表的sql语句,其中视图不用理会:
表之间的部门关系如下:
一个采购商pa_agent通过关联表responsible关联一个part。
多个同类part组成一个product(可以理解为多个同学组成一个班,同学都是属于学生种类)。
一种product由一个供应商supplier供应。
一个订单purchase_order由一个采购商pa_agent发出给一个供应商supplier,订单与采购商通过关联表pa_task关联。
订单的发出人,供应人,购买product数量,总价,状态,保存在detail表中。
写得不是太好,但从我学习历程来看,重点难点应该是 Pro*C 程序 SQL 嵌入以及预编译、编译那部分。
实践能力强的小伙伴不妨建一个简单的表,写一个简单查询的 Pro*C 程序。