首页 > 代码库 > 数据库编程4 Oracle Pro*C/C++开发

数据库编程4 Oracle Pro*C/C++开发

本文谢绝转载原文来自http://990487026.blog.51cto.com


1,上次难点复习
	1 求所有部门的平均奖金
	2 求各部门的平均薪水
	3 求各部门每个工种的平均薪水
	4 求各部门每个工种大于2000的平均薪水
	5 求10号部门的平均工资(2种写法)
	6 创建一个学生表
	7 并向表中插入一条数据
	8 列出不是管理层的员工:
	9 工资最高前10名的员工信息(rownum是一个属性值)
	10 找到各部门大于本部门平均薪水的员工:
	11 创建索引
Linux 环境 Oracle  Pro*C Oracle 编程:
	官方文档
	Linux 下Oracle数据库的环境部署
	配置proc编译器
	配置vim 为pc文件高亮
	Proc*C/C++编译配置
	Oracle数据类型
	proc小试身手
	C语言方式:SQL 内嵌语法:
	C++方式,SQL 内嵌语法,proc编译c++需要配置一下
	Pro*C 编程:insert into 向数据库插入数据:
	Pro*C 编程:update  向数据库更新数据:
	Pro*C 编程:select从数据库查数据:之char数据类型
	Pro*C varchar 数据类型,自动去除占位的空格
	Pro*C string数据类型,自动去除占位的空格
	NULL问题,1,插入数据时,字段填NULL
	NULL问题,2,获取数据时,判断是否为NULL
	Pro*C/C++ 编程,向Oracle 插入中文
		先把Linux,Oracle,Sqlplus设置为UTF8
	Oracle 通讯区 和错误处理:
	游标的官方文档
	游标与数组:查询多条记录,全部插入一张表中
	用普通游标提取数据,一行一行的获取数据,就像单向链表
	用滚动游标提取数据,可查询指定任意行数据:指哪儿打哪儿
	[难点]动态SQL,1,只能使用非select语法
	[难点]动态SQL,2,非查询语言, 带固定数量的宿主变量
	[难点]动态SQL,3 处理选择列表项(select查询出来的结果列数固定)
	[难点]动态SQL4,具备完整select 语法 ANSI方法
	[难点]动态SQL4,具备完整select 语法Oracle官方方法	
	
		
		


复习

1 求所有部门的平均奖金

SQL> select avg(comm) from emp;

 AVG(COMM)
----------
       550

SQL> select avg(nvl(comm,0)) from emp;

AVG(NVL(COMM,0))
----------------
      115.789474


2 求各部门的平均薪水

SQL> select deptno, avg(sal) from emp group by deptno;

    DEPTNO   AVG(SAL)
---------- ----------
        30 1566.66667
        20 3839.28571
        10     4187.5


3 求各部门每个工种的平均薪水

SQL> select deptno, job, avg(sal) from emp group by deptno, job;

    DEPTNO JOB         AVG(SAL)
---------- --------- ----------
        20 CLERK            950
        30 SALESMAN        1400
        20 MANAGER         2975
        30 CLERK            950
        10 PRESIDENT       5000
        20 clerk           8000
        30 MANAGER         2850
        10 CLERK           1300
        20
        10 MANAGER         2450
        20 ANALYST         3000
        10                 8000

12 rows selected.



4 求各部门每个工种大于2000的平均薪水

SQL> select deptno, job, avg(sal) from emp group by deptno, job having avg(sal) >2000;

    DEPTNO JOB         AVG(SAL)
---------- --------- ----------
        20 MANAGER         2975
        10 PRESIDENT       5000
        20 clerk           8000
        30 MANAGER         2850
        10 MANAGER         2450
        20 ANALYST         3000
        10                 8000

7 rows selected.


5 求10号部门的平均工资(2种写法)

1:

SQL> select deptno,avg(sal) from emp group by deptno having deptno=10;

    DEPTNO   AVG(SAL)
---------- ----------
        10     4187.5

2:

SQL> select deptno,avg(sal) from emp where deptno=10 group by deptno;

    DEPTNO   AVG(SAL)
---------- ----------
        10     4187.5	
	
	



6 创建一个学生表

	sid
	sname	
	email
	sex
	age
SQL> create table studet (sid number(2) primary key, sname varchar2(50) not null,email varchar2(50), sex varchar2(1),age number(2));

Table created.

SQL> desc studet;
 Name              Null?    Type
 ------------------------- -------- -----------------------
 SID               NOT NULL NUMBER(2)
 SNAME             NOT NULL VARCHAR2(14)
 EMAIL                      VARCHAR2(20)
 SEX                        VARCHAR2(1)
 AGE                        NUMBER(2)


7 并向表中插入一条数据

SQL> insert into studet values(10,‘鲁智深‘,‘Linux‘,‘m‘,20);
1 row created.


8 列出不是管理层的员工:

SQL> select * from emp where empno not in  (select mgr from emp  where mgr is not null);

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
         1 tom_abc                                         8000                    10
         2 aaa        clerk           7092 17-DEC-80       8000                    20
         3 abc                                                                     20
         4 aaa        clerk           7092 26-AUG-16       8000                    20
         5 chunli                                                                  20
      7369 SMITH      CLERK           7902 17-DEC-80        800                    20
      7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300         30
      7521 WARD       SALESMAN        7698 22-FEB-81       1250        500         30
      7654 MARTIN     SALESMAN        7698 28-SEP-81       1250       1400         30
      7844 TURNER     SALESMAN        7698 08-SEP-81       1500          0         30
      7876 ADAMS      CLERK           7788 23-MAY-87       1100                    20
      7900 JAMES      CLERK           7698 03-DEC-81        950                    30
      7934 MILLER     CLERK           7782 23-JAN-82       1300                    10


9,显示工资最高前10名的员工信息(rownum是一个属性值):

SQL> select * from (select * from emp order by sal desc nulls last) where rownum <= 10;

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
         1 tom_abc                                         8000                    10
         4 aaa        clerk           7092 26-AUG-16       8000                    20
         2 aaa        clerk           7092 17-DEC-80       8000                    20
      7839 KING       PRESIDENT            17-NOV-81       5000                    10
      7788 SCOTT      ANALYST         7566 19-APR-87       3000                    20
      7902 FORD       ANALYST         7566 03-DEC-81       3000                    20
      7566 JONES      MANAGER         7839 02-APR-81       2975                    20
      7698 BLAKE      MANAGER         7839 01-MAY-81       2850                    30
      7782 CLARK      MANAGER         7839 09-JUN-81       2450                    10
      7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300         30

10 rows selected.



10 ,找到各部门大于本部门平均薪水的员工:

SQL> select d.deptno, d.avgsal,e.ename,e.sal from emp e, (select deptno,avg(sal) avgsal from emp group by deptno) d where e.deptno=d.deptno and sal>=avgsal;

    DEPTNO     AVGSAL ENAME             SAL
---------- ---------- ---------- ----------
        30 1566.66667 ALLEN            1600
        30 1566.66667 BLAKE            2850
        10     4187.5 KING             5000
        10     4187.5 tom_abc          8000
        20 3839.28571 aaa              8000
        20 3839.28571 aaa              8000

6 rows selected.


创建索引:

SQL> desc studet;  
 Name               Null?    Type
 ----------------- -------- -------- ------------
 SID                NOT NULL NUMBER(2)
 SNAME              NOT NULL VARCHAR2(14)
 EMAIL                       VARCHAR2(20)
 SEX                         VARCHAR2(1)
 AGE                         NUMBER(2)

 
SQL> create index student_index on studet (sname);
SQL> desc studet;
 Name             Null?    Type
 ------------------------ -------- ---------------------
 SID              NOT NULL NUMBER(2)
 SNAME            NOT NULL VARCHAR2(14)
 EMAIL                     VARCHAR2(20)
 SEX                       VARCHAR2(1)
 AGE                       NUMBER(2)





Linux 环境 Oracle  Pro*C Oracle 编程:

官方文档:Pro*C/C++ Programmer‘s Guide:

http://docs.oracle.com/cd/E11882_01/appdev.112/e10825/toc.htm



Linux 下Oracle数据库的安装,

可以参考我的笔记:http://990487026.blog.51cto.com/10133282/1843639



配置proc编译器:

[oracle@oracle11 proc]$ vim /opt/oracle/app/product/11.2.0/dbhome_1/precomp/admin/pcscfg.cfg

在后面加:/usr/lib/gcc/x86_64-redhat-linux/4.4.4/include

变成这样的:
[oracle@oracle11 ~]$ cat /opt/oracle/app/product/11.2.0/dbhome_1/precomp/admin/pcscfg.cfg
sys_include=($ORACLE_HOME/precomp/public,/usr/include,/usr/lib/gcc-lib/x86_64-redhat-linux/3.2.3/include,/usr/lib/gcc/x86_64-redhat-linux/4.1.1/include,/usr/lib64/gcc/x86_64-suse-linux/4.1.0/include,/usr/lib64/gcc/x86_64-suse-linux/4.3/include,/usr/lib/gcc/x86_64-redhat-linux/4.4.4/include)
ltype=short
define=__x86_64__
[oracle@oracle11 ~]$ 


如果不配置:
Proc 编译,出现错误PCC-S-02015, unable to open include file
加选项parse=no也可以解决



[配置]vim 为pc文件高亮

[oracle@oracle11 ~]$ cat /home/oracle/.vimrc 
autocmd BufEnter *.pc set filetype=esqlc


[Proc*C/C++编译配置]

proc的头文件在:/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/
proc的动态库在:/opt/oracle/app/product/11.2.0/dbhome_1/lib/
编译示例:$ proc hello.pc > /dev/null && gcc hello.c  -I/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/ -L/opt/oracle/app/product/11.2.0/dbhome_1/lib/ -lclntsh  && ./a.out


Oracle数据类型

技术分享


proc小试身手

[oracle@oracle11 proc]$ cat hello.pc
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
	printf("Hello \n");
	return 0;
}
[oracle@oracle11 proc]$ 
proc编译:[oracle@oracle11 proc]$ proc parse=no hello.pc 
gcc 编译:[oracle@oracle11 proc]$ gcc hello.c && ./a.out 
Hello 



一键联编:
[oracle@oracle11 proc]$ proc hello.pc > /dev/null && gcc hello.c && ./a.out
Hello 
[oracle@oracle11 proc]$



C语言方式:SQL 内嵌语法:

[oracle@oracle11 proc]$ cat hello.pc
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqlca.h"

//定义宿主变量
EXEC SQL BEGIN DECLARE SECTION;
	char *serverid="scott/11@orcl";
EXEC SQL END DECLARE SECTION;

int main()
{
	int ret = 0;
	printf("Hello \n");
	//嵌入式SQL语句必须以 EXEC SQL  开头
	EXEC SQL connect:serverid;//妈蛋,这是谁龟腚的语法
	if(sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode;
		printf("EXEC SQL connect:serverid err \n");
		exit(1);
	}
	printf("connect ok!\n");

	return ret;
}
[oracle@oracle11 proc]$ proc hello.pc > /dev/null && gcc hello.c  -I/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/ -L/opt/oracle/app/product/11.2.0/dbhome_1/lib/ -lclntsh  && ./a.out
Hello 
connect ok!
[oracle@oracle11 proc]$ 


编译很烦:Makefile就好用了
[oracle@oracle11 proc]$ proc hello.pc > /dev/null
[oracle@oracle11 proc]$ gcc hello.c	-I/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/ 					-L/opt/oracle/app/product/11.2.0/dbhome_1/lib/ -lclntsh  
[oracle@oracle11 proc]$ ./a.out


C++方式,SQL 内嵌语法:

[oracle@oracle11 proc]$ cat c++_hello.pc

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include "sqlca.h"
using namespace std;

//定义宿主变量
EXEC SQL BEGIN DECLARE SECTION;
	char *serverid="scott/11@orcl";
EXEC SQL END DECLARE SECTION;

int main()
{
	int ret = 0;
	//printf("Hello \n");
	cout << "hello c++ sql\n";
	//嵌入式SQL语句必须以 EXEC SQL  开头
	EXEC SQL connect:serverid;//妈蛋,这是谁龟腚的语法
	if(sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode;
		cout<<"EXEC SQL connect:serverid err \n";
		exit(1);
	}
	cout<<"connect ok!\n";
	return ret;
}
[oracle@oracle11 proc]$ proc iname=./c++_hello.pc oname=c++_hello.cpp PARSE=NONE CODE=cpp > /dev/null && g++ c++_hello.cpp  -I/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/ -L/opt/oracle/app/product/11.2.0/dbhome_1/lib/ -lclntsh  && ./a.out
c++_hello.cpp:153: warning: deprecated conversion from string constant to ‘char*’
hello c++ sql
connect ok!
[oracle@oracle11 proc]$ 




proc编译c++需要配置一下

[oracle@oracle11 proc]
$ proc iname=./c++_hello.pc oname=c++_hello.cpp PARSE=NONE CODE=cpp > /dev/null && g++ c++_hello.cpp  	-I/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/			-L/opt/oracle/app/product/11.2.0/dbhome_1/lib/ -lclntsh && ./a.out




Pro*C 编程:insert into 向数据库插入数据:

[oracle@oracle11 proc]$ cat db_op.pc 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqlca.h"

//定义宿主变量
EXEC SQL BEGIN DECLARE SECTION;
	char *serverid="scott/11@orcl";
	int deptno = 0;
	char dname[20];
	char loc[20];
EXEC SQL END DECLARE SECTION;

int main()
{
	int ret = 0;
	printf("Hello \n");
	//嵌入式SQL语句必须以 EXEC SQL  开头
	EXEC SQL connect:serverid;
	if(sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode;
		printf("EXEC SQL connect:serverid err \n");
		exit(1);
	}
	deptno  =50;
	strcpy(dname,"oracle");
	strcpy(loc,"China");
	EXEC SQL insert into dept (deptno,dname,loc) values(:deptno,:dname,:loc);
	EXEC SQL commit;
	//EXEC SQL commit RELEASE;提交事务并断开连接

	printf("connect ok!\n");

	return ret;
}

[oracle@oracle11 proc]$ cat comp 
INCLUDE_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/
LD_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/lib/
proc db_op.pc
gcc db_op.c  -I$INCLUDE_PATH -L$LD_PATH -lclntsh  
./a.out

[oracle@oracle11 proc]$ bash comp 
Pro*C/C++: Release 11.2.0.1.0 - Production on Mon Aug 29 03:09:12 2016
Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.
System default option values taken from: /opt/oracle/app/product/11.2.0/dbhome_1/precomp/admin/pcscfg.cfg
Hello 
connect ok!


开一个窗口:验证
SQL> select * from dept;

    DEPTNO DNAME	  LOC
---------- -------------- -------------
	50 oracle	  China
	10 ACCOUNTING	  NEW YORK
	20 RESEARCH	  DALLAS
	30 SALES	  CHICAGO
	40 OPERATIONS	  BOSTON	




Pro*C 编程:update  向数据库更新数据:

[oracle@oracle11 proc]$ cat db_op.pc
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqlca.h"

//定义宿主变量
EXEC SQL BEGIN DECLARE SECTION;
	char *serverid="scott/11@orcl";
	int deptno = 0;
	char dname[20];
	char loc[20];
EXEC SQL END DECLARE SECTION;

int main()
{
	int ret = 0;
	printf("Hello \n");
	//嵌入式SQL语句必须以 EXEC SQL  开头
	EXEC SQL connect:serverid;
	if(sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode;
		printf("EXEC SQL connect:serverid err \n");
		exit(1);
	}
	deptno  =50;
	strcpy(dname,"oracle");
	strcpy(loc,"England");
	EXEC SQL update  dept set loc = :loc where deptno=:deptno;
	EXEC SQL commit;
	//EXEC SQL commit RELEASE;提交事务并断开连接

	printf("connect ok!\n");

	return ret;
}
[oracle@oracle11 proc]$ 

编译小脚本:
[oracle@oracle11 proc]$ cat comp 
INCLUDE_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/
LD_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/lib/

proc db_op.pc
gcc db_op.c  -I$INCLUDE_PATH -L$LD_PATH -lclntsh  
./a.out


编译:
[oracle@oracle11 proc]$ bash comp 

Pro*C/C++: Release 11.2.0.1.0 - Production on Mon Aug 29 03:14:01 2016

Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.

System default option values taken from: /opt/oracle/app/product/11.2.0/dbhome_1/precomp/admin/pcscfg.cfg

Hello 
connect ok!

验证:
SQL> select * from dept;

    DEPTNO DNAME	  LOC
---------- -------------- -------------
	50 oracle	  England
	10 ACCOUNTING	  NEW YORK
	20 RESEARCH	  DALLAS
	30 SALES	  CHICAGO
	40 OPERATIONS	  BOSTON

SQL>


Pro*C 编程:select从数据库查数据:之char数据类型

[oracle@oracle11 proc]$ cat db_op.pc
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqlca.h"
EXEC SQL BEGIN DECLARE SECTION;//定义宿主变量
	char *serverid="scott/11@orcl";
	int deptno = 0;
	char dname[20];
	char loc[20];
EXEC SQL END DECLARE SECTION;
int main()
{
	int ret = 0;
	printf("Hello \n");
	EXEC SQL connect:serverid;	//嵌入式SQL语句必须以 EXEC SQL  开头
	if(sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode;
		printf("EXEC SQL connect:serverid err \n");
		exit(1);
	}
	printf("connect ok!\n");
	strcpy(loc,"DALLAS");
	EXEC SQL select deptno,dname,loc into:deptno,:dname,:loc from dept where loc=:loc;
	printf("deptno=%d,dname=%s,loc=%s\n",deptno,dname,loc);
	//EXEC SQL commit RELEASE;提交事务并断开连接
	return ret;
}
[oracle@oracle11 proc]$ cat  comp 
INCLUDE_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/
LD_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/lib/

proc db_op.pc
gcc db_op.c  -I$INCLUDE_PATH -L$LD_PATH -lclntsh  
./a.out


[oracle@oracle11 proc]$ bash comp 

Pro*C/C++: Release 11.2.0.1.0 - Production on Mon Aug 29 03:33:54 2016

Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.

System default option values taken from: /opt/oracle/app/product/11.2.0/dbhome_1/precomp/admin/pcscfg.cfg

Hello 
connect ok!
deptno=20,dname=RESEARCH           ,loc=DALLAS             
[oracle@oracle11 proc]$


Pro*C varchar 数据类型,自动去除占位的空格

[oracle@oracle11 proc]$ cat main.pc
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqlca.h"
EXEC SQL BEGIN DECLARE SECTION;//定义宿主变量,这可不是C风格的变量,虽然看起来像
	char *serverid="scott/11@orcl";
	int deptno = 0;
	char dname[20];
	char loc[20];

	int deptno2;
	varchar dname2[20];
	varchar loc2[20];
EXEC SQL END DECLARE SECTION;
int main()
{
	int ret = 0;
	printf("正在连接ORACLE  \n");
	EXEC SQL connect:serverid;	//嵌入式SQL语句必须以 EXEC SQL  开头
	if(sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode;
		printf("EXEC SQL connect:serverid err \n");
		exit(1);
	}
	printf("连接成功!\n");

	strcpy(loc,"DALLAS");
	EXEC SQL select deptno,dname,loc into:deptno,:dname,:loc from dept where loc=:loc;
	printf("char SQL 风格:	deptno=%d,dname=%s,loc=%s\n",deptno,dname,loc);
	EXEC SQL select deptno,dname,loc into:deptno2,:dname2,:loc2 from dept where deptno=20;
	//printf("varcher SQL风格:deptno=%d,dname=%s,loc=%s\n",deptno2,dname2,loc2);
	printf("varcher SQL风格:deptno=%d,dname=%s,loc=%s\n",deptno2,dname2.arr,loc2.arr);

	//EXEC SQL commit RELEASE;提交事务并断开连接
	return ret;
}
[oracle@oracle11 proc]$ 


编译小脚本:
[oracle@oracle11 proc]$ cat comp 
INCLUDE_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/
LD_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/lib/

proc main.pc
gcc main.c  -I$INCLUDE_PATH -L$LD_PATH -lclntsh  
./a.out


开始编译运行:
[oracle@oracle11 proc]$ bash comp 

Pro*C/C++: Release 11.2.0.1.0 - Production on Mon Aug 29 09:42:37 2016

Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.

System default option values taken from: /opt/oracle/app/product/11.2.0/dbhome_1/precomp/admin/pcscfg.cfg

正在连接ORACLE  
连接成功!
char SQL 风格:	deptno=20,dname=RESEARCH           ,loc=DALLAS             
varcher SQL风格:deptno=40,dname=OPERATIONS,loc=BOSTON
[oracle@oracle11 proc]$ bash comp 

Pro*C/C++: Release 11.2.0.1.0 - Production on Mon Aug 29 09:42:59 2016

Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.

System default option values taken from: /opt/oracle/app/product/11.2.0/dbhome_1/precomp/admin/pcscfg.cfg

正在连接ORACLE  
连接成功!
char SQL 风格:	deptno=20,dname=RESEARCH           ,loc=DALLAS             
varcher SQL风格:deptno=20,dname=RESEARCH,loc=DALLAS
[oracle@oracle11 proc]$



Pro*C string数据类型,自动去除占位的空格

[oracle@oracle11 proc]$ cat main.pc
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqlca.h"
typedef char dnameType[20];
typedef char locType[20];
EXEC SQL BEGIN DECLARE SECTION;//定义宿主变量,这可不是C风格的变量,虽然看起来像
	char *serverid="scott/11@orcl";
	int deptno_1;
	char dname_1[20];
	char loc_1[20];

	EXEC SQL TYPE dnameType is string(20);
	EXEC SQL TYPE locType is string(20);
	int deptno_2;
	dnameType dname_2;
	locType loc_2;
EXEC SQL END DECLARE SECTION;
int main()
{
	int ret = 0;
	printf("正在连接ORACLE  \n");
	EXEC SQL connect:serverid;	//嵌入式SQL语句必须以 EXEC SQL  开头
	if(sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode;
		printf("EXEC SQL connect:serverid err \n");
		exit(1);
	}
	printf("连接成功!\n");

	EXEC SQL select deptno,dname,loc into:deptno_1,:dname_1,:loc_1 from dept where deptno=20;
	printf("char   SQL 风格:deptno=%d,dname=%s,loc=%s\n",deptno_1,dname_1,loc_1);
	EXEC SQL select deptno,dname,loc into:deptno_2,:dname_2,:loc_2 from dept where deptno=20;
	printf("string SQL 风格:deptno=%d,dname=%s,loc=%s\n",deptno_2,dname_2,loc_2);

	//EXEC SQL commit RELEASE;提交事务并断开连接
	return ret;
}
编译小脚本:
[oracle@oracle11 proc]$ cat  comp 
INCLUDE_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/
LD_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/lib/
proc main.pc
gcc main.c  -I$INCLUDE_PATH -L$LD_PATH -lclntsh  
./a.out


编译运行:
[oracle@oracle11 proc]$ bash comp 
正在连接ORACLE  
连接成功!
char   SQL 风格:deptno=20,dname=RESEARCH           ,loc=DALLAS             
string SQL 风格:deptno=20,dname=RESEARCH,loc=DALLAS
[oracle@oracle11 proc]$



NULL问题,1,插入数据时,字段填NULL

[oracle@oracle11 proc]$ cat main.pc
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqlca.h"
typedef char dnameType[20];
typedef char locType[20];
EXEC SQL BEGIN DECLARE SECTION;//定义宿主变量,这可不是C风格的变量,虽然看起来像
	char *serverid="scott/11@orcl";
	int   deptno;
	char  dname[20];
	short dname_ind;	//指示器变量
	char  loc[20];
	short loc_ind;		//指示器变量

	EXEC SQL TYPE dnameType is string(20);
	EXEC SQL TYPE locType is string(20);
	int deptno_2;
	dnameType dname_2;
	locType loc_2;
EXEC SQL END DECLARE SECTION;
int main()
{
	int ret = 0;
	printf("正在连接ORACLE  \n");
	EXEC SQL connect:serverid;	//嵌入式SQL语句必须以 EXEC SQL  开头
	if(sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode;
		printf("EXEC SQL connect:serverid err \n");
		exit(1);
	}
	printf("连接成功!\n");
	
	loc_ind = -1;
	deptno = 60;
	strcpy(dname,"oracle");
	strcpy(loc,"China");
	EXEC SQL insert into dept (deptno,dname,loc) values(:deptno,:dname,:loc:loc_ind);
	EXEC SQL commit RELEASE;	//提交事务并断开连接

	return ret;
}
编译小脚本:
[oracle@oracle11 proc]$ cat comp 
INCLUDE_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/
LD_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/lib/
proc main.pc
gcc main.c  -I$INCLUDE_PATH -L$LD_PATH -lclntsh  
./a.out


[oracle@oracle11 proc]$ 


编译运行:
[oracle@oracle11 proc]$ bash comp 

Pro*C/C++: Release 11.2.0.1.0 - Production on Mon Aug 29 10:50:00 2016

Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.

System default option values taken from: /opt/oracle/app/product/11.2.0/dbhome_1//precomp/admin/pcscfg.cfg

正在连接ORACLE  
连接成功!
[oracle@oracle11 proc]$ 


验证:
SQL> select * from dept;

    DEPTNO DNAME	  LOC
---------- -------------- -------------
	60 oracle
	50 oracle	  England
	10 ACCOUNTING	  NEW YORK
	20 RESEARCH	  DALLAS
	30 SALES	  CHICAGO
	40 OPERATIONS	  BOSTON

6 rows selected.


NULL问题,2,获取数据时,判断是否为NULL

[oracle@oracle11 proc]$ cat main.pc 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqlca.h"
typedef char dnameType[20];
typedef char locType[20];
EXEC SQL BEGIN DECLARE SECTION;//定义宿主变量,这可不是C风格的变量,虽然看起来像
	char *serverid="scott/11@orcl";
	int   deptno;
	char  dname[20];
	short dname_ind;	//指示器变量
	char  loc[20];
	short loc_ind;		//指示器变量

	EXEC SQL TYPE dnameType is string(20);
	EXEC SQL TYPE locType is string(20);
	int deptno_2;
	dnameType dname_2;
	locType loc_2;
EXEC SQL END DECLARE SECTION;
int main()
{
	int ret = 0;
	printf("正在连接ORACLE  \n");
	EXEC SQL connect:serverid;	//嵌入式SQL语句必须以 EXEC SQL  开头
	if(sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode;
		printf("EXEC SQL connect:serverid err \n");
		exit(1);
	}
	printf("连接成功!\n");
	
	loc_ind = -1;
	deptno = 60;
	EXEC SQL select deptno, dname, loc into :deptno, :dname, :loc:loc_ind from dept where deptno=:deptno;
	if(loc_ind == -1)
	{
		strcpy(loc,"NULL");
	}
	printf("deptno=%d,dname=%s,loc=%s\n",deptno,dname,loc);

	loc_ind = -1;
	deptno = 30;
	EXEC SQL select deptno, dname, loc into :deptno, :dname, :loc:loc_ind from dept where deptno=:deptno;
	if(loc_ind == -1)
	{
		strcpy(loc,"NULL");
	}
	printf("deptno=%d,dname=%s,loc=%s\n",deptno,dname,loc);
	EXEC SQL commit RELEASE;	//提交事务并断开连接
	return ret;
}
编译小脚本:
[oracle@oracle11 proc]$ cat comp 
INCLUDE_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/
LD_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/lib/
proc main.pc
gcc main.c  -I$INCLUDE_PATH -L$LD_PATH -lclntsh  
./a.out

编译运行:
[oracle@oracle11 proc]$ bash comp 

Pro*C/C++: Release 11.2.0.1.0 - Production on Mon Aug 29 11:13:24 2016

Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.

System default option values taken from: /opt/oracle/app/product/11.2.0/dbhome_1//precomp/admin/pcscfg.cfg

正在连接ORACLE  
连接成功!
deptno=60,dname=oracle             ,loc=NULL
deptno=30,dname=SALES              ,loc=CHICAGO            
[oracle@oracle11 proc]$ 


验证:
SQL> select * from dept;

    DEPTNO DNAME	  LOC
---------- -------------- -------------
	60 oracle
	50 oracle	  England
	10 ACCOUNTING	  NEW YORK
	20 RESEARCH	  DALLAS
	30 SALES	  CHICAGO
	40 OPERATIONS	  BOSTON

6 rows selected.


Pro*C/C++ 编程,向Oracle 插入中文:

先把Linux,Oracle,Sqlplus设置为UTF8:

http://990487026.blog.51cto.com/10133282/1843858

[oracle@oracle11 proc]$ cat main.pc 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqlca.h"
EXEC SQL BEGIN DECLARE SECTION;//定义宿主变量,这可不是C风格的变量,虽然看起来像
	char *serverid="scott/11@orcl";
	int   deptno;
	char  dname[20];
	char  loc[20];
EXEC SQL END DECLARE SECTION;
int main()
{
	int ret = 0;
	printf("正在连接ORACLE  \n");
	EXEC SQL connect:serverid;	//嵌入式SQL语句必须以 EXEC SQL  开头
	if(sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode;
		printf("EXEC SQL connect:serverid err \n");
		exit(1);
	}
	printf("连接成功!\n");
	deptno = 52;
	strcpy(dname,"浙");
	strcpy(loc,"江");
	EXEC SQL insert into dept(deptno,dname,loc) values(:deptno,:dname,:loc);
	EXEC SQL commit RELEASE;	//提交事务并断开连接
	return ret;
}
[oracle@oracle11 proc]$ 

编译小脚本:
[oracle@oracle11 proc]$ cat comp 
INCLUDE_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/
LD_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/lib/
proc main.pc
gcc main.c  -I$INCLUDE_PATH -L$LD_PATH -lclntsh  
./a.out

编译运行:
[oracle@oracle11 proc]$ bash comp 
Pro*C/C++: Release 11.2.0.1.0 - Production on Mon Aug 29 13:38:08 2016
Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.
System default option values taken from: /opt/oracle/app/product/11.2.0/dbhome_1/precomp/admin/pcscfg.cfg
正在连接ORACLE  
连接成功!
[oracle@oracle11 proc]$ 

验证:
SQL> select * from dept;
        52 浙             江
	10 ACCOUNTING	  NEW YORK
	20 RESEARCH	  DALLAS
	30 SALES	  CHICAGO
	40 OPERATIONS	  BOSTON

6 rows selected.



Oracle 通讯区 和错误处理:

[oracle@oracle11 proc]$ find /opt/oracle/ -name sqlca.h

/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/sqlca.h

演示登陆密码错误:

[oracle@oracle11 proc]$ cat main.pc 
#include <stdio.h>
#include  <string.h>
#include <stdlib.h>
#include "sqlca.h"
EXEC SQL BEGIN  DECLARE SECTION ;//先定义宿主变量 (SQL变量)
	char * serverid = "scott/tiger22@orcl";
	int 	deptid;
	char	DNAME[32];
	char  	LOC[32];
EXEC SQL END  DECLARE SECTION ;

void sqlerr02()	//错误SQL语言给打印出来
{
	char	stm[120];
	size_t	sqlfc, stmlen=120;
	unsigned int ret = 0;
	printf("func sqlerr02() begin\n");
	
	EXEC SQL WHENEVER SQLERROR CONTINUE; 	//出错时,可以把错误SQL语言给打印出来
	ret = sqlgls(stm, &stmlen, &sqlfc);
	/*
	if (ret != 0)
	{
		printf("func sqlgls() err, %d \n", ret);
		return ;
	}*/
	printf("中国\n");
	printf("出错的SQL:%.*s\n", stmlen, stm);
	printf("出错原因:%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
	//printf("出错原因:%.70s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
	EXEC SQL ROLLBACK WORK RELEASE;
	printf("func sqlerr02() end\n");
	exit(1);
}


void sqlerr()	//出错原因
{
	EXEC SQL WHENEVER SQLERROR CONTINUE; // 下一步
	printf("err reason:%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
	//printf("err reason:%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
	EXEC SQL ROLLBACK WORK RELEASE;//
	exit(1);
}


//main===> serverid==>sqlerr()==>EXEC SQL ROLLBACK WORK RELEASE;/==>sqlerr()
int main()
{
	int	ret = 0;
	printf("hello....\n");
	printf("serverid:%s \n", serverid);
	deptid = 63;
	strcpy(DNAME, "50name");
	strcpy(LOC, "50loc");
	EXEC SQL WHENEVER SQLERROR DO sqlerr();
	EXEC SQL connect :serverid;
	if (sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode ;
		printf("connect err:%d \n", ret);
		return ret;
	}
	else
	{
		printf("connect ok\n");
	}
	
	EXEC SQL insert into dept(DEPTNO, DNAME, LOC) values(:deptid, :DNAME, :LOC);
	EXEC SQL COMMIT; 
	printf("anter key continue ...delete...\n");
	getchar();
	getchar();
	//EXEC SQL delete from dept where deptno= :deptid;
	printf("anter key continue ...update...\n");
	getchar();
	getchar();
	strcpy(LOC, "50loclolo");
	strcpy(LOC, "中国");
	EXEC SQL update dept set loc= :LOC where deptno= :deptid; 
	EXEC SQL COMMIT RELEASE; //提交事务断开连接
	return ret;	
}


编译小脚本
[oracle@oracle11 proc]$ cat comp 
INCLUDE_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/
LD_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/lib/
proc main.pc
gcc main.c  -I$INCLUDE_PATH -L$LD_PATH -lclntsh  
./a.out

编译运行
[oracle@oracle11 proc]$ bash comp 
hello....
serverid:scott/tiger22@orcl 
err reason:ORA-01017: invalid username/password; logon denied
[oracle@oracle11 proc]$



oerr错误码查看

[oracle@oracle11 proc]$ oerr ora 1017
01017, 00000, "invalid username/password; logon denied"
// *Cause:
// *Action:
[oracle@oracle11 proc]$



游标的官方文档:

Cursors:

http://docs.oracle.com/cd/E11882_01/appdev.112/e10825/pc_06sql.htm#i2206





游标与数组:查询多条记录,全部插入一张表中


1,先创建一个空表:

SQL> create table like_dept as select * from dept where 1=2;
SQL> select * from like_dept;
no rows selected

程序:

[oracle@oracle11 proc]$ cat  main.pc 
#include <stdio.h>
#include  <string.h>
#include <stdlib.h>
#include "sqlca.h"
EXEC SQL BEGIN  DECLARE SECTION ;	//先定义宿主变量 (SQL变量)
	char * serverid = "scott/11@orcl";
	int		deptno[100];
	char		dname[100][20];
	char 		loc[100][20];
	int		count;
	int		deptno2[100];
	varchar		dname2[100][20]; 
	varchar 	loc2[100][20];
	short 		loc_ind[100];
EXEC SQL END  DECLARE SECTION ;



//错误SQL语言给打印出来
void sqlerr02()
{
	char	stm[120];
	size_t	sqlfc, stmlen=120;
	unsigned int ret = 0;
	printf("func sqlerr02() begin\n");

	//出错时,可以把错误SQL语言给打印出来
	EXEC SQL WHENEVER SQLERROR CONTINUE;

	ret = sqlgls(stm, &stmlen, &sqlfc);
	/*
	   if (ret != 0)
	   {
	   printf("func sqlgls() err, %d \n", ret);
	   return ;
	   }*/
	printf("中国\n");

	printf("出错的SQL:%.*s\n", stmlen, stm);
	printf("出错原因:%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
	//printf("出错原因:%.70s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
	EXEC SQL ROLLBACK WORK RELEASE;
	printf("func sqlerr02() end\n");
	exit(1);
}

//出错原因
void sqlerr()
{
	EXEC SQL WHENEVER SQLERROR CONTINUE; // 下一步
	printf("err reason:%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
	//printf("err reason:%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
	EXEC SQL ROLLBACK WORK RELEASE;//
	exit(1);
}



int main()
{
	int ret = 0; 
	int i = 0;
	int count;
	printf("位于主函数\n");
	EXEC SQL WHENEVER SQLERROR DO sqlerr();	
	printf("已执行  EXEC SQL WHENEVER SQLERROR DO sqlerr()\n");
	EXEC SQL connect :serverid;
	//EXEC SQL WHENEVER NOT FOUND CONTINUE;
	printf("111111111111....\n");

	EXEC SQL select deptno, dname, loc into :deptno2, :dname2, :loc2:loc_ind from dept ;
	printf("22222222....\n");
	count=	sqlca.sqlerrd[2];
	printf("select 返回%d条记录 \n", count);
	for (i=0; i<count; i++)
	{
		printf("%d, %s, %s\n", deptno2[i], dname2[i].arr, loc2[i].arr);
	}
	printf("333333333....\n");

	EXEC SQL FOR :count insert into like_dept(deptno, dname, loc) values(:deptno2, :dname2, :loc2);
	EXEC SQL COMMIT RELEASE; //提交事务断开连接
	return ret;	
}


[oracle@oracle11 proc]$ cat comp 
INCLUDE_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/
LD_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/lib/
proc main.pc
gcc main.c  -I$INCLUDE_PATH -L$LD_PATH -lclntsh  
./a.out
[oracle@oracle11 proc]$ bash comp 
位于主函数
已执行  EXEC SQL WHENEVER SQLERROR DO sqlerr()
111111111111....
22222222....
select 返回4条记录 
10, ACCOUNTING, NEW YORK
20, RESEARCH, DALLAS
30, SALES, CHICAGO
40, OPERATIONS, BOSTON
333333333....
[oracle@oracle11 proc]$ 

验证:
SQL> select * from like_dept;
	10 ACCOUNTING	  NEW YORK
	20 RESEARCH	  DALLAS
	30 SALES	  CHICAGO
	40 OPERATIONS	  BOSTON

SQL>



用普通游标提取数据,一行一行的获取数据,就像单向链表

1,打造环境,建表填中文数据:

SQL> create table student (sid number(2) primary key, sname varchar2(50) not null,ADDRESS varchar2(50), sex varchar2(1),age number(2));
SQL> insert into student values(10,‘宋江‘,‘梁山第一把交椅‘,‘M‘,40);
SQL> insert into student values(20,‘林冲‘,‘豹子头‘,‘M‘,30);
SQL> insert into student values(20,‘吴用‘,‘智多星‘,‘M‘,30);
SQL> insert into student values(22,‘吴用‘,‘智多星‘,‘M‘,30);
SQL> insert into student values(23,‘鲁智深‘,‘花和尚‘,‘M‘,30);
SQL> insert into student values(21,‘燕青‘,‘李师师‘,‘M‘,23);
SQL> insert into student values(11,‘李逵‘,‘黑旋风‘,‘M‘,23);
SQL> insert into student values(12,‘王伦‘,‘火并王伦‘,‘M‘,33);
SQL> insert into student values(13,‘扈三娘‘,‘王爱虎‘,‘M‘,33);
SQL> insert into student values(14,‘高俅老二‘,‘高衙内‘,‘M‘,33);
SQL> insert into student values(15,‘西门庆‘,‘潘金莲‘,‘M‘,33);
SQL> insert into student values(16,‘镇关西‘,‘卖猪肉‘,‘M‘,33);
SQL> select * from student;  
10 宋江        梁山第一把交椅  M         40  
20 林冲        豹子头          M         30  
22 吴用        智多星          M         30  
23 鲁智深      花和尚          M         30  
21 燕青        李师师          M         23  
11 李逵        黑旋风          M         23  
12 王伦        火并王伦        M         33  
13 扈三娘      王爱虎          M         33  
14 高俅老二    高衙内          M         33  
15 西门庆      潘金莲          M         33  
16 镇关西      卖猪肉          M         33  
SQL> commit;
Commit complete.


主程序:

[oracle@oracle11 proc]$ cat main.pc 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sqlca.h"
typedef char dnameType[80];
typedef char locType[80];

//演示普通游标查询数据
//需要注意点:如果程序查不到数据,要break出来 否则程序死循环
//游标中使用宿主数组提取数据 ----oracle9i proc*C/C++编程指南  第九章练习题4
//用游标来更新或者删除数据

EXEC SQL BEGIN DECLARE SECTION;
EXEC SQL TYPE dnameType is string(50);
EXEC SQL TYPE locType is string(50);
	char 	*usrname = "scott";
	char 	*passwd = "11";
	char 	*serverid = "orcl";
	int	deptno;
	dnameType		dname; //string 数据类型  
	short 			dname_ind;
	locType 		loc;
	short 			loc_ind;	
EXEC SQL END DECLARE SECTION;

extern sqlgls(char * , size_t *, size_t * );
extern sqlglmt(void *,char *,size_t *,size_t *);

void connet()
{
	int ret = 0;
	//连接数据库
	EXEC SQL CONNECT:usrname IDENTIFIED BY:passwd USING:serverid ;
	if (sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode;
		printf("sqlca.sqlcode: err:%d \n", sqlca.sqlcode);
		return ;
	}
	else
	{
		printf("connect ok...\n");
	}
}

void sqlerr02()
{
	char	stm[120];
	size_t	sqlfc, stmlen=120;
	unsigned int ret = 0;
	//出错时,可以把错误SQL语言给打印出来
	EXEC SQL WHENEVER SQLERROR CONTINUE;
	ret = sqlgls(stm, &stmlen, &sqlfc);	
	printf("出错的SQL:%.*s\n", stmlen, stm);
	printf("出错原因:%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
	//printf("出错原因:%.70s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
	EXEC SQL ROLLBACK WORK RELEASE;
	exit(1);
}

void nodata()
{
	int ret = 0;
	printf("没有发现数据\n");
	if (sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode;
		printf("sqlca.sqlcode: err:%d \n", sqlca.sqlcode);
		return ;
	}
}


int main()
{
	int ret = 0;	
	int i = 0;
	EXEC SQL WHENEVER SQLERROR DO sqlerr02();
	connet();
	EXEC SQL DECLARE c CURSOR FOR select SID,SNAME,ADDRESS from student;		//1。定义游标
	//EXEC SQL DECLARE c CURSOR FOR select deptno,dname,loc from dept;		//1。定义游标
	EXEC SQL  OPEN c ;								//2.  打开游标
	EXEC SQL WHENEVER NOT FOUND DO BREAK;						//3.  提取数据 fetch into
	while (1) 
	{
		//printf("haha\n");
		EXEC SQL FETCH c INTO :deptno,:dname,:loc:loc_ind;
		if (loc_ind == -1)
		{
			strcpy(loc, "null");
		}
		printf("条目数:%d\t", sqlca.sqlerrd[2]);
		printf("%d, %s, %s \n", deptno, dname, loc);
	}
	EXEC SQL CLOSE c;								//4 关闭游标
	EXEC SQL COMMIT WORK RELEASE;
	return ret ;
}

编译运行:
[oracle@oracle11 proc]$ cat comp 
INCLUDE_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/
LD_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/lib/
proc main.pc
gcc main.c  -I$INCLUDE_PATH -L$LD_PATH -lclntsh  
[oracle@oracle11 proc]$ bash comp 
[oracle@oracle11 proc]$ ./a.out 
connect ok...
条目数:1	10, 宋江, 梁山第一把交椅 
条目数:2	20, 林冲, 豹子头 
条目数:3	22, 吴用, 智多星 
条目数:4	23, 鲁智深, 花和尚 
条目数:5	21, 燕青, 李师师 
条目数:6	11, 李逵, 黑旋风 
条目数:7	12, 王伦, 火并王伦 
条目数:8	13, 扈三娘, 王爱虎 
条目数:9	14, 高俅老二, 高衙内 
条目数:10	15, 西门庆, 潘金莲 
条目数:11	16, 镇关西, 卖猪肉 
[oracle@oracle11 proc]$



用滚动游标提取数据,可查询指定任意行数据:指哪儿打哪儿

相当于双向链表:数据库和表就用上面的例子

[oracle@oracle11 proc]$ cat main.pc 
//演示滚动游标查询数据
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sqlca.h"
typedef char dnameType[20];
typedef char locType[20];
extern sqlgls(char * , size_t *, size_t * );
extern sqlglmt(void *,char *,size_t *,size_t *);

EXEC SQL BEGIN DECLARE SECTION;
EXEC SQL TYPE dnameType is string(20);
EXEC SQL TYPE locType is string(20);
char 	*usrname = "scott";
char 	*passwd = "11";
char 	*serverid = "orcl";

int			deptno;
dnameType		dname; //string 数据类型  
short 			dname_ind;
locType 		loc;
short 			loc_ind;	
EXEC SQL END DECLARE SECTION;

void connet()
{
	int ret = 0;
	//连接数据库
	EXEC SQL CONNECT:usrname IDENTIFIED BY:passwd USING:serverid ;
	if (sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode;
		printf("sqlca.sqlcode: err:%d \n", sqlca.sqlcode);
		return ;
	}
	else
	{
		printf("connect ok...\n");
	}
}

void sqlerr02()
{
	char	stm[120];
	size_t	sqlfc, stmlen=120;
	unsigned int ret = 0;

	//出错时,可以把错误SQL语言给打印出来
	EXEC SQL WHENEVER SQLERROR CONTINUE;

	ret = sqlgls(stm, &stmlen, &sqlfc);	
	printf("出错的SQL:%.*s\n", stmlen, stm);
	printf("出错原因:%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
	//printf("出错原因:%.70s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
	EXEC SQL ROLLBACK WORK RELEASE;
	exit(1);
}

void nodata()
{
	int ret = 0;
	printf("没有发现数据\n");
	if (sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode;
		printf("sqlca.sqlcode: err:%d \n", sqlca.sqlcode);
		return ;
	}
}

int main()
{
	int ret = 0;	
	int i = 0;
	EXEC SQL WHENEVER SQLERROR DO sqlerr02();
	connet();
	//EXEC SQL WHENEVER NOT FOUND DO nodata();
	//1 定义游标  declare cursor  在为某一次查询
	EXEC SQL DECLARE c SCROLL  CURSOR FOR 	select sid, sname,ADDRESS from student;
	EXEC SQL OPEN c;		//2 打开游标 open cursor 

	//EXEC SQL WHENEVER NOT FOUND DO break;
	//3 获取数据 fetch data

	//查询最后一条数据
	EXEC SQL FETCH LAST c INTO :deptno, :dname:dname_ind, :loc:loc_ind;
	//printf("条目数:%d\t", sqlca.sqlerrd[2]);
	printf("%d\t %s\t %s \n", deptno, dname, loc );

	//查询第一条数据
	EXEC SQL FETCH FIRST c INTO :deptno, :dname:dname_ind, :loc:loc_ind;
	//printf("条目数:%d\t", sqlca.sqlerrd[2]);
	printf("%d\t %s\t %s \n", deptno, dname, loc );

	//查询第3条数据
	EXEC SQL FETCH ABSOLUTE 3 c INTO :deptno, :dname:dname_ind, :loc:loc_ind;
	//printf("条目数:%d\t", sqlca.sqlerrd[2]);
	printf("%d\t %s\t %s \n", deptno, dname, loc );

	//查询相对第3条数据 也就是第6条
	EXEC SQL FETCH RELATIVE 3 c INTO :deptno, :dname:dname_ind, :loc:loc_ind;
	//printf("条目数:%d\t", sqlca.sqlerrd[2]);
	printf("%d\t %s\t %s \n", deptno, dname, loc );

	//查询下一条
	EXEC SQL FETCH NEXT c INTO :deptno, :dname:dname_ind, :loc:loc_ind;
	//printf("条目数:%d\t", sqlca.sqlerrd[2]);
	printf("%d\t %s\t %s \n", deptno, dname, loc );

	//查询前一条
	EXEC SQL FETCH PRIOR  c INTO :deptno, :dname:dname_ind, :loc:loc_ind;
	//printf("条目数:%d\t", sqlca.sqlerrd[2]);
	printf("%d\t %s\t %s \n", deptno, dname, loc );

	//4 关闭游标 close data
	EXEC SQL CLOSE c;	
	EXEC SQL COMMIT WORK RELEASE;
	printf("return ok...\n");
	return ret ;
}

[oracle@oracle11 proc]$ cat comp 
INCLUDE_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/
LD_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/lib/
proc main.pc
gcc main.c  -I$INCLUDE_PATH -L$LD_PATH -lclntsh  
[oracle@oracle11 proc]$ bash comp 

Pro*C/C++: Release 11.2.0.1.0 - Production on Mon Aug 29 16:43:31 2016

Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.

System default option values taken from: /opt/oracle/app/product/11.2.0/dbhome_1/precomp/admin/pcscfg.cfg

[oracle@oracle11 proc]$ ./a.out 
connect ok...
16	 镇关西	 卖猪肉 
10	 宋江	 梁山第一把交
22	 吴用	 智多星 
11	 李逵	 黑旋风 
12	 王伦	 火并王伦 
11	 李逵	 黑旋风 
return ok...
[oracle@oracle11 proc]$


[难点]动态SQL,1,只能使用非select语法

[oracle@oracle11 proc]$ cat main.pc 
//演示dynamic-sql四种方法
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sqlca.h"
#include "oraca.h"

extern sqlgls(char * , size_t *, size_t * );
extern sqlglmt(void *,char *,size_t *,size_t *);
typedef char dnameType[20];
typedef char locType[20];
EXEC SQL BEGIN DECLARE SECTION;
EXEC SQL TYPE dnameType is string(20);
EXEC SQL TYPE locType is string(20);
char 	*usrname = "scott";
char 	*passwd = "11";
char 	*serverid = "orcl";
int			deptno;
dnameType		dname; //string 数据类型  //varchar类型 和 char 类型的区别. 与编译选项有关系
short 			dname_ind;
locType 		loc;
short 			loc_ind;	
char 			mySql[1024];
char 			*pSql;
EXEC SQL END DECLARE SECTION;

void connet()
{
	int ret = 0;
	//连接数据库
	EXEC SQL CONNECT:usrname IDENTIFIED BY:passwd USING:serverid ;
	if (sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode;
		printf("sqlca.sqlcode: err:%d \n", sqlca.sqlcode);
		return ;
	}
	else
	{
		printf("connect ok...\n");
	}
}

void sqlerr02()
{
	char	stm[120];
	size_t	sqlfc, stmlen=120;
	unsigned int ret = 0;

	//出错时,可以把错误SQL语言给打印出来
	EXEC SQL WHENEVER SQLERROR CONTINUE;

	ret = sqlgls(stm, &stmlen, &sqlfc);	
	printf("出错的SQL:%.*s\n", stmlen, stm);
	printf("出错原因:%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
	//printf("出错原因:%.70s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
	EXEC SQL ROLLBACK WORK RELEASE;
	exit(1);
}

void nodata()
{
	int ret = 0;
	printf("没有发现数据\n");
	if (sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode;
		printf("sqlca.sqlcode: err:%d \n", sqlca.sqlcode);
		return ;
	}
}

//非select语言,无宿主变量
int main()
{
	int 	ret = 0;	
	int 	i = 0;
	char    choosechar;
	memset(mySql, 0, sizeof(mySql));
	pSql = NULL;
	EXEC SQL WHENEVER SQLERROR DO sqlerr02();
	connet();
	//EXEC SQL WHENEVER NOT FOUND DO nodata();
	pSql = mySql;
	//循环处理sql语言
	while(1)
	{
		printf("\nplease enter sql(not select ): ");
		gets(mySql);
		//scanf("%s", mySql); --空格截断
		printf("mysql:%s\n", mySql);
		printf("任意键继续....\n");
		//getchar();
		EXEC SQL EXECUTE IMMEDIATE :pSql;

		EXEC SQL COMMIT;
		printf("继续执行吗?\n");
		scanf("%c", &choosechar);
		fflush(stdin);
		if (choosechar==‘n‘ || choosechar==‘N‘)
		{
			break;
		}
	}
	EXEC SQL COMMIT WORK RELEASE;
	printf("return ok...\n");
	return ret ;
}

[oracle@oracle11 proc]$ cat comp 
INCLUDE_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/
LD_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/lib/
proc main.pc
gcc main.c  -I$INCLUDE_PATH -L$LD_PATH -lclntsh  

编译:
[oracle@oracle11 proc]$ bash comp 
运行:
[oracle@oracle11 proc]$ ./a.out 
connect ok...

please enter sql(not select ): insert into dept values(68, ‘中‘, ‘国‘)                 
mysql:insert into dept values(68, ‘中‘, ‘国‘)
任意键继续....
继续执行吗?
n
return ok...
[oracle@oracle11 proc]$ 


验证:
SQL> select * from dept;
        68 中             国
	10 ACCOUNTING	  NEW YORK
	20 RESEARCH	  DALLAS
	30 SALES	  CHICAGO
	40 OPERATIONS	  BOSTON


[难点]动态SQL,2,非查询语言, 带固定数量的宿主变量

//非查询语言, 带固定数量的宿主变量
//使用内嵌PREPARE命令准备SQL语言
//动态sql2 有2步骤
//1 PREPARE语法
EXEC SQL PREPARE statement_name FROM {:host_string | string_literal};
PREPARE是一个预编译器标识符,而不是宿主变量
//2 USING子句
EXEC SQL EXECUTE statement_name [USING :host_variable1[:indicator1] [, :host_variable2[:indicator2] ...  ] ;



[oracle@oracle11 proc]$ cat main.pc 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sqlca.h"
#include "oraca.h"

extern sqlgls(char * , size_t *, size_t * );
extern sqlglmt(void *,char *,size_t *,size_t *);
typedef char dnameType[20];
typedef char locType[20];
EXEC SQL BEGIN DECLARE SECTION;
	EXEC SQL TYPE dnameType is string(20);
	EXEC SQL TYPE locType is string(20);
	char 	*usrname = "scott";
	char 	*passwd = "11";
	char 	*serverid = "orcl";
	
	int				deptno;
	dnameType		dname; //string 数据类型  //varchar类型 和 char 类型的区别. 与编译选项有关系
	short 			dname_ind;
	locType 		loc;
	short 			loc_ind;	
	char 			mySql[1024];
	char 			*pSql;
EXEC SQL END DECLARE SECTION;
void connet()
{
	int ret = 0;
	//连接数据库
	EXEC SQL CONNECT:usrname IDENTIFIED BY:passwd USING:serverid ;
	if (sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode;
		printf("sqlca.sqlcode: err:%d \n", sqlca.sqlcode);
		return ;
	}
	else
	{
		printf("connect ok...\n");
	}
}

void sqlerr02()
{
	char	stm[120];
	size_t	sqlfc, stmlen=120;
	unsigned int ret = 0;
	
	//出错时,可以把错误SQL语言给打印出来
	EXEC SQL WHENEVER SQLERROR CONTINUE;
	
	ret = sqlgls(stm, &stmlen, &sqlfc);	
	printf("出错的SQL:%.*s\n", stmlen, stm);
	printf("出错原因:%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
	//printf("出错原因:%.70s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
	EXEC SQL ROLLBACK WORK RELEASE;
	exit(1);
}

void nodata()
{
	int ret = 0;
	printf("没有发现数据\n");
	if (sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode;
		printf("sqlca.sqlcode: err:%d \n", sqlca.sqlcode);
		return ;
	}
}

int main()
{
	int 	ret = 0;	
	int 	i = 0;
	char    choosechar;

	memset(mySql, 0, sizeof(mySql));
	pSql = NULL;
	
	EXEC SQL WHENEVER SQLERROR DO sqlerr02();
	connet();
	//EXEC SQL WHENEVER NOT FOUND DO nodata();
	
	pSql = mySql;
	//循环处理sql语言
	for(;;)
	{
		printf("\n请输入要更新部门编号 ");
		scanf("%d", &deptno);
		
		printf("\n请输入要新loc值 ");
		scanf("%s", loc);
		
	
		//准备动态sql
		EXEC SQL PREPARE my_pre_sql FROM ‘update dept set loc = :a where deptno = :b‘;
		//执行动态sql
		EXEC SQL EXECUTE my_pre_sql USING :loc, :deptno;  //
	
		EXEC SQL COMMIT;
		
		printf("\n 按任意键继续? ");
		getchar();
		printf("\n退出键入n, 其他继续? ");
		scanf("%c", &choosechar);
		fflush(stdin);
		
		if (choosechar==‘n‘ || choosechar==‘N‘)
		{
			break;
		}
	}

	EXEC SQL COMMIT WORK RELEASE;
	printf("return ok...\n");

	return ret ;
}




[oracle@oracle11 proc]$ cat comp 
INCLUDE_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/
LD_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/lib/
proc main.pc
gcc main.c  -I$INCLUDE_PATH -L$LD_PATH -lclntsh  
[oracle@oracle11 proc]$ 

编译运行:
[oracle@oracle11 proc]$ bash comp 
[oracle@oracle11 proc]$ ./a.out 
connect ok...
请输入要更新部门编号 68
请输入要新loc值 浙江
 按任意键继续? 
退出键入n, 其他继续? n
return ok...
[oracle@oracle11 proc]$ 

验证:
SQL> select * from dept;
        68 中             国
	10 ACCOUNTING	  NEW YORK
	20 RESEARCH	  DALLAS
	30 SALES	  CHICAGO
	40 OPERATIONS	  BOSTON

SQL> select * from dept;
        68 中             浙江
	10 ACCOUNTING	  NEW YORK
	20 RESEARCH	  DALLAS
	30 SALES	  CHICAGO
	40 OPERATIONS	  BOSTON

SQL>


[难点]动态SQL,3 处理选择列表项(select查询出来的结果列数固定)

查询部门号大于10的所有部门信息
动态sql3 处理选择列表项(select查询出来的结果列数固定) 和 输入宿主变量个数一定
本质:	输入宿主变量个数固定 	查询条件固定  
输出宿主变量个数固定	返回结果固定
可以结合游标一块使用
[oracle@oracle11 proc]$ cat main.pc 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sqlca.h"
#include "oraca.h"

extern sqlgls(char * , size_t *, size_t * );
extern sqlglmt(void *,char *,size_t *,size_t *);
typedef char dnameType[20];
typedef char locType[20];
EXEC SQL BEGIN DECLARE SECTION;
	EXEC SQL TYPE dnameType is string(20);
	EXEC SQL TYPE locType is string(20);
	char 	*usrname = "scott";
	char 	*passwd = "11";
	char 	*serverid = "orcl";
	
	int				deptno;
	dnameType		dname; //string 数据类型  //varchar类型 和 char 类型的区别. 与编译选项有关系
	short 			dname_ind;
	locType 		loc;
	short 			loc_ind;	
	char 			mySql[1024];
	char 			*pSql;
EXEC SQL END DECLARE SECTION;
void connet()
{
	int ret = 0;
	//连接数据库
	EXEC SQL CONNECT:usrname IDENTIFIED BY:passwd USING:serverid ;
	if (sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode;
		printf("sqlca.sqlcode: err:%d \n", sqlca.sqlcode);
		return ;
	}
	else
	{
		printf("connect ok...\n");
	}
}

void sqlerr02()
{
	char	stm[120];
	size_t	sqlfc, stmlen=120;
	unsigned int ret = 0;
	
	//出错时,可以把错误SQL语言给打印出来
	EXEC SQL WHENEVER SQLERROR CONTINUE;
	
	ret = sqlgls(stm, &stmlen, &sqlfc);	
	printf("出错的SQL:%.*s\n", stmlen, stm);
	printf("出错原因:%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
	//printf("出错原因:%.70s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
	EXEC SQL ROLLBACK WORK RELEASE;
	exit(1);
}

void nodata()
{
	int ret = 0;
	printf("没有发现数据\n");
	if (sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode;
		printf("sqlca.sqlcode: err:%d \n", sqlca.sqlcode);
		return ;
	}
}


int main()
{
	int 	ret = 0;	
	int 	i = 0;
	char    choosechar;
	memset(mySql, 0, sizeof(mySql));
	pSql = NULL;
	EXEC SQL WHENEVER SQLERROR DO sqlerr02();
	connet();
	//EXEC SQL WHENEVER NOT FOUND DO nodata();
	//循环处理sql语言
	printf("程序会输出大于指定部门编号的所有信息\n");
	while(1)
	{
		printf("请输入部门编号 ");
		scanf("%d", &deptno);
		EXEC SQL PREPARE my_pre_sql3 FROM ‘select deptno, dname, loc from dept where deptno > :a‘;//准备动态sql
		EXEC SQL DECLARE c1 CURSOR FOR my_pre_sql3;			//定义游标
		EXEC SQL OPEN c1 USING :deptno;					//打开游标
		EXEC SQL WHENEVER NOT FOUND DO break;				//提取数据
		for (;;)
		{
			EXEC SQL FETCH c1 INTO :deptno, :dname,:loc:loc_ind;
			printf("%d,%s,%s\n", deptno, dname, loc); 
		}
		EXEC SQL CLOSE c1;
		EXEC SQL COMMIT;
		printf("\n键入 n 退出, 其他继续\n");
		scanf("%c", &choosechar);
		fflush(stdin);
		if (choosechar==‘n‘ || choosechar==‘N‘)
		{
			break;
		}
	}
	EXEC SQL COMMIT WORK RELEASE;
	printf("return ok...\n");
	return ret ;
}	

[oracle@oracle11 proc]$ cat comp 
INCLUDE_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/
LD_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/lib/
proc main.pc
gcc main.c  -I$INCLUDE_PATH -L$LD_PATH -lclntsh  
[oracle@oracle11 proc]$ bash comp 

Pro*C/C++: Release 11.2.0.1.0 - Production on Mon Aug 29 18:23:41 2016

Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.

System default option values taken from: /opt/oracle/app/product/11.2.0/dbhome_1/precomp/admin/pcscfg.cfg

[oracle@oracle11 proc]$ ./a.out 
connect ok...
程序会输出大于指定部门编号的所有信息
请输入部门编号 11
20,RESEARCH,DALLAS
30,SALES,CHICAGO
40,OPERATIONS,BOSTON
68,中,杭州

键入 n 退出, 其他继续
请输入部门编号 n

键入 n 退出, 其他继续
return ok...
[oracle@oracle11 proc]$ 

验证:
SQL> select * from dept;
        68 中             杭州
	10 ACCOUNTING	  NEW YORK
	20 RESEARCH	  DALLAS
	30 SALES	  CHICAGO
	40 OPERATIONS	  BOSTON

SQL>



[难点]动态SQL4,具备完整select 语法 ANSI方法

支持任意列宽的select
proc编译选项:
MODE=ANSI|ISO|ANSI14|ISO14|ANSI13|ISO13|ORACLE;
缺省值为ORACLE。指定程序遵循的标准。
[难,5年的员工看起来也吃力]Oracle开发就是这么难!!!!


主程序:
[oracle@oracle11 proc]$ cat main.pc 

/* sqlcheck=full */  
/* userid=scott/password@exam */  
/* mode=ansi */  

// proc  
  
/* 包含C头文件 */  
#include <stdio.h>  
#include <string.h>  
  
/* 包含SQLCA头文件 */  
#include <sqlca.h>  

/* 定义绑定变量值和 选择列表项值的最大长度 */  
#define MAX_VAR_LEN     30 

/* 定义选择列表项名的最大长度 */  
#define MAX_NAME_LEN    31  
  

/* 定义宿主变量 */  
exec sql begin declare section; 
	char 	*usrname = "scott";
	char 	*passwd = "11";
	char 	*serverid = "orcl"; 
    char sql_stat[100];  
    char current_date[20];  
exec sql end declare section;  
  
void sql_error();  
void connet();
void process_input();  
void process_output();  
  
int main()  
{  
    /* 安装错误处理句柄 */  
    exec sql whenever sqlerror do sql_error();  
  
    /* 连接到数据库 */  
    connet();  
  
    /* 分配输入描述区和输出描述区 */  
    exec sql allocate descriptor ‘input_descriptor‘;  
    exec sql allocate descriptor ‘output_descriptor‘;  
  
    for( ; ; )  
    {  
        printf("\n请输入动态SQL语句(EXIT:退出):\n");  
        gets(sql_stat);  
  
        /* EXIT(exit)->退出 */  
        if(0 == strncmp(sql_stat , "EXIT" , 4) || 0 == strncmp(sql_stat , "exit" , 4))  
            break;  
  
        /* 准备动态SQL语句 */  
        exec sql prepare s from :sql_stat;  
  
        /* 定义游标 */  
        exec sql declare c cursor for s;  
  
        /* 处理绑定变量 */  
        process_input();  
  
        /* 打开游标 
         * select语句:处理查询结果 
         * 其他SQL语句:执行 
        */  
        exec sql open c using descriptor ‘input_descriptor‘;  
        if(0 == strncmp(sql_stat , "SELECT" , 6) , 0 == strncmp(sql_stat , "select" , 6))  
        {  
			process_output();
        }  
        /* 关闭游标 */  
        exec sql close c;  
    }  
  
    /* 释放输入描述区和输出描述区 */  
    exec sql deallocate descriptor ‘input_descriptor‘;  
    exec sql deallocate descriptor ‘output_descriptor‘;  
  
    /* 提交事务,断开连接 */  
    exec sql commit work release;  
    puts("谢谢使用ANSI动态SQL!\n");  
  
    return 0;  
}  
  
void sql_error()  
{  
    /* 显示SQL错误 */  
    printf("%.*s\n" , sqlca.sqlerrm.sqlerrml , sqlca.sqlerrm.sqlerrmc);  
    exit(0);
}  
  
void process_input()  
{  
    int i;  
  
    /* 定义宿主变量 */  
    exec sql begin declare section;  
        int input_count;  
        int input_type ;  
        int input_len;  
        char input_buffer[MAX_VAR_LEN];  
        char name[MAX_NAME_LEN];  
        int occurs;  
    exec sql end declare section;  
  
    /* 绑定变量->输入描述区 */  
    exec sql describe input s using descriptor ‘input_descriptor‘;  
  
    /* 取得绑定变量个数 */  
    exec sql get descriptor ‘input_descriptor‘ :input_count = count;  
  
    /* 循环处理绑定变量名 */  
    for(i = 0 ; i != input_count ; ++i)  
    {  
        occurs = i + 1;  
  
        /* 取得绑定变量名 */  
        exec sql get descriptor ‘input_descriptor‘ value :occurs :name = name;  
        printf("请输入%s的值:" , name);  
        gets(input_buffer);  
  
        /* 以NULL结尾 */  
        input_len = strlen(input_buffer);  
        input_buffer[input_len] = ‘\0‘;  
  
        /* 设置绑定变量类型、长度和值 */  
        input_type = 1;  
        exec sql set descriptor ‘input_descriptor‘ value :occurs   
            type = :input_type , length = :input_len , data = :input_buffer;  
    }  
}  
  
void process_output()  
{  
    int i;  
  
    // 定义宿主变量  
    EXEC SQL BEGIN DECLARE SECTION ;  
   
        int output_count;  
        int output_type;  
        int output_len;  
        char output_buffer[MAX_VAR_LEN];
        short  output_indicator;  
        char name[MAX_NAME_LEN];  
        int occurs;  
    EXEC SQL END DECLARE SECTION ;  
  
 
    // 选择列表项->输出描述区 
    exec sql describe output s using descriptor ‘output_descriptor‘;  
  
    //取得选择列表项个数  
    exec sql get descriptor ‘output_descriptor‘ :output_count = count;  
  
 
    //循环处理选择列表项 (显示表头;设置显示。数据按照字符串格式)
    
    output_type = 12;  //note //设置类型为变长字符串
    //output_type = 1;  //note
    for(i = 0 ; i != output_count ; ++i)  
    {  
        occurs = i + 1;  
        
        output_len = MAX_VAR_LEN;  
      
      //printf("22222222222222:%d \n", i);
        // 设置选择列表项的类型和长度 
        exec sql set descriptor ‘output_descriptor‘ value :occurs   
            type = :output_type , length = :output_len;  
  
        //取得选择列表项的名称并输出 
        exec sql get descriptor ‘output_descriptor‘ value :occurs :name = name;  
        	
        //显示选择列表项名称  
        printf("\t%s" , name);  
    }  
    printf("\n");  
  
    // 提取数据完毕->退出循环  
    exec sql whenever not found do break;  
  
    // 循环处理选择列表项数据  
    for( ; ; )  
    {  
        // 行数据->输出描述区  
        exec sql fetch c into descriptor ‘output_descriptor‘;  
           
        // 循环处理每列数据  
        for(i = 0 ; i < output_count ; ++i)  
        {  
            occurs = i +1;  
           
            // 取得列数据和指示变量值  
            exec sql get descriptor ‘output_descriptor‘ VALUE :occurs  
                :output_buffer = DATA , :output_indicator = INDICATOR;  
  
            //输出列数据   
            if(-1 == output_indicator)  
               printf("\t%s", "   ");         
            else  
               printf("\t%s" , output_buffer);        
        }  
         
        printf("\n"); 
    }  
   
}


void connet()
{
	int ret = 0;
	//连接数据库
	EXEC SQL CONNECT:usrname IDENTIFIED BY:passwd USING:serverid ;
	if (sqlca.sqlcode != 0)
	{
		ret = sqlca.sqlcode;
		printf("sqlca.sqlcode: err:%d \n", sqlca.sqlcode);
		return ;
	}
	else
	{
		printf("connect ok...\n");
	}
}
[oracle@oracle11 proc]$ 


编译小脚本:
[oracle@oracle11 proc]$ cat comp 
INCLUDE_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/
LD_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/lib/
proc mode=ansi  main.pc
gcc main.c  -I$INCLUDE_PATH -L$LD_PATH -lclntsh  
[oracle@oracle11 proc]$ 

编译运行:
[oracle@oracle11 proc]$ bash comp 

Pro*C/C++: Release 11.2.0.1.0 - Production on Mon Aug 29 19:10:40 2016

Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.

System default option values taken from: /opt/oracle/app/product/11.2.0/dbhome_1/precomp/admin/pcscfg.cfg

main.c: In function ‘sql_error’:
main.c:440: warning: incompatible implicit declaration of built-in function ‘exit’
/tmp/ccys6Bg9.o: In function `main‘:
main.c:(.text+0x174): warning: the `gets‘ function is dangerous and should not be used.

运行:
[oracle@oracle11 proc]$ ./a.out 
connect ok...

请输入动态SQL语句(EXIT:退出):
select * from dept
	DEPTNO	DNAME	LOC
	68	中	杭州
	10	ACCOUNTING	NEW YORK
	20	RESEARCH	DALLAS
	30	SALES	CHICAGO
	40	OPERATIONS	BOSTON

请输入动态SQL语句(EXIT:退出):
exit
谢谢使用ANSI动态SQL!

[oracle@oracle11 proc]$ 
[oracle@oracle11 proc]$ ./a.out 
connect ok...

请输入动态SQL语句(EXIT:退出):
select * from emp
	EMPNO	ENAME	JOB	MGR	HIREDATE	SAL	COMM	DEPTNO
	7369	SMITH	CLERK	7902	17-DEC-80	800	   	20
	7499	ALLEN	SALESMAN	7698	20-FEB-81	1600	300	30
	7521	WARD	SALESMAN	7698	22-FEB-81	1250	500	30
	7566	JONES	MANAGER	7839	02-APR-81	2975	   	20
	7654	MARTIN	SALESMAN	7698	28-SEP-81	1250	1400	30
	7698	BLAKE	MANAGER	7839	01-MAY-81	2850	   	30
	7782	CLARK	MANAGER	7839	09-JUN-81	2450	   	10
	7788	SCOTT	ANALYST	7566	19-APR-87	3000	   	20
	7839	KING	PRESIDENT	   	17-NOV-81	5000	   	10
	7844	TURNER	SALESMAN	7698	08-SEP-81	1500	0	30
	7876	ADAMS	CLERK	7788	23-MAY-87	1100	   	20
	7900	JAMES	CLERK	7698	03-DEC-81	950	   	30
	7902	FORD	ANALYST	7566	03-DEC-81	3000	   	20
	7934	MILLER	CLERK	7782	23-JAN-82	1300	   	10

请输入动态SQL语句(EXIT:退出):
exit 
谢谢使用ANSI动态SQL!

[oracle@oracle11 proc]$ 



验证:
SQL> select * from dept;
        68 中             杭州
	10 ACCOUNTING	  NEW YORK
	20 RESEARCH	  DALLAS
	30 SALES	  CHICAGO
	40 OPERATIONS	  BOSTON

SQL> select * from emp;
      7369 SMITH      CLERK	      7902 17-DEC-80		  800			 20
      7499 ALLEN      SALESMAN	      7698 20-FEB-81		 1600	     300	 30
      7521 WARD       SALESMAN	      7698 22-FEB-81		 1250	     500	 30
      7566 JONES      MANAGER	      7839 02-APR-81		 2975			 20
      7654 MARTIN     SALESMAN	      7698 28-SEP-81		 1250	    1400	 30
      7698 BLAKE      MANAGER	      7839 01-MAY-81		 2850			 30
      7782 CLARK      MANAGER	      7839 09-JUN-81		 2450			 10
      7788 SCOTT      ANALYST	      7566 19-APR-87		 3000			 20
      7839 KING       PRESIDENT 	   17-NOV-81		 5000			 10
      7844 TURNER     SALESMAN	      7698 08-SEP-81		 1500	       0	 30
      7876 ADAMS      CLERK	      7788 23-MAY-87		 1100			 20
      7900 JAMES      CLERK	      7698 03-DEC-81		  950			 30
      7902 FORD       ANALYST	      7566 03-DEC-81		 3000			 20
      7934 MILLER     CLERK	      7782 23-JAN-82		 1300			 10

14 rows selected.

SQL>




[难点]动态SQL4,具备完整select 语法Oracle官方方法  

 
方法4,Oracle官方方法,可做简历案例
难点1,内存分配
难点2,数据的展示

[oracle@oracle11 proc]$ cat main.pc 
/* 包含C头文件 */  
#include <stdio.h>  
#include <string.h>  
#include <stdlib.h>  
#include <setjmp.h>  
#include <sqlcpr.h>  
  
/* 包含SQLDA和SQLCA结构 */  
#include <sqlda.h>  
#include <sqlca.h>  
  
/* 定义绑定变量和选择列表项的最大个数 */  
#define MAX_ITEMS       40  
  
/* 定义绑定变量和选择列表项名称的最大长度 */  
#define MAX_VNAME_LEN   30  
  
/* 定义指示变量名称的最大长度 */  
#define MAX_INAME_LEN   30  
  
void connect();  
void sql_error();  
void alloc_descriptors(int , int , int);  
void dealloc_descriptors();  
void set_bind_variables();  
void process_select_list();  
  
/* 定义绑定描述区和选择描述区 */  
SQLDA* bind_dp;  
SQLDA* select_dp;  
  
/* 定义输入宿主变量:存放动态SQL语句 */  
char sql_stat[100];   
char current_date[20];     
  
int main()  
{  
    /* 安装错误处理句柄 */  
    exec sql whenever sqlerror do sql_error();  
  
    /* 连接到数据库 */  
    connect2();  
  
    /* 分配绑定描述区和选择描述区 */  
    alloc_descriptors(MAX_ITEMS , MAX_VNAME_LEN , MAX_INAME_LEN);  
  
    for( ; ; )  
    {  
        printf("请输入动态SQL语句(exit:退出):");  
        gets(sql_stat);  
  
        /* EXIT(exit):退出 */  
        if(0 == strncmp(sql_stat , "exit" , 4) || 0 == strncmp(sql_stat , "EXIT" , 4))  
            break;  
  
        /* 准备动态SQL语句 */  
        exec sql prepare s from :sql_stat;  
  
        /* 定义游标 */  
        exec sql declare c cursor for s;  
  
        /* 出错,继续下一循环 */  
        if(0 != sqlca.sqlcode)  
            continue;  
  
        /* 设置绑定变量 */  
        set_bind_variables();  
  
        /* 
         * 打开游标 
         * select语句:生成结果集 
         * 其他SQL语句:执行语句 
         */  
        exec sql open c using descriptor bind_dp;  
  
        /* 
         * select语句 
         */  
        if(0 == strncmp(sql_stat , "select" , 6) || 0 == strncmp(sql_stat , "SELECT" , 6)) 
		{  
            process_select_list();   
        }  
        /* 关闭游标 */  
        exec sql close c;  
    }  
  
    /* 释放选择描述区和选择描述区 */  
    dealloc_descriptors();  
  
    /* 提交事务,断开连接 */  
    exec sql commit work release;  
    puts("谢谢使用Oracle动态SQL方法四!\n");  
  
    return 0;  
}  

 
void connect2()  
{  
    /* 定义宿主变量 */  
    char username[20] , password[20] , server[20];  
  
    /* 输入用户名、口令和网络服务名 */  
    printf("username:");  
    gets(username);  
  
    printf("password: ");  
    gets(password);  
  
    printf("server:");  
    gets(server);  
  
    /* 连接到数据库 */  
    EXEC SQL CONNECT :username identified by :password using :server;  
}  


//struct SQLDA {
  /* ub4    */ int        N; /* Descriptor size in number of entries        */
  /* text** */ char     **V; /* Ptr to Arr of addresses of main variables   */
  /* ub4*   */ int       *L; /* Ptr to Arr of lengths of buffers            */
  /* sb2*   */ short     *T; /* Ptr to Arr of types of buffers              */
  /* sb2**  */ short    **I; /* Ptr to Arr of addresses of indicator vars   */
  /* sb4    */ int        F; /* Number of variables found by DESCRIBE       */
  /* text** */ char     **S; /* Ptr to Arr of variable name pointers        */
  /* ub2*   */ short     *M; /* Ptr to Arr of max lengths of var. names     */
  /* ub2*   */ short     *C; /* Ptr to Arr of current lengths of var. names */
  /* text** */ char     **X; /* Ptr to Arr of ind. var. name pointers       */
  /* ub2*   */ short     *Y; /* Ptr to Arr of max lengths of ind. var. names*/
  /* ub2*   */ short     *Z; /* Ptr to Arr of cur lengths of ind. var. names*/
 // };
  
  /*
 char ** getMeme(int size)
 {
 	int i;
 		char **tmp = (char **)malloc(sizeof(char *) *size);
 		
 		for (i=0; i<size; i++)
 		{
 			tmp[i] = (char *)malloc(40);
 		}
 		return tmp;
 		
 }
  
void SQLSQLDAAlloc(0 , size , MAX_VNAME_LEN , MAX_INAME_LEN)
{
	struct SQLDA  *sqlda = (struct SQLDA  *)malloc(sizeof(struct SQLDA ));
	sqlda->v = (char     **)malloc(sizeof(char *) * size);
	sqlda->I = (char     **)malloc(sizeof(char *) * size);
	sqlda->S = (char     **)malloc(sizeof(char *) * size);
	sqlda->X = (char     **)malloc(sizeof(char *) * size);
	
	sqlda->L = (int *)malloc(size*sizeof(int));
	 sqlda->T = (short *)malloc(size*sizeof(short));
	
	
	//..
	//....
	return sqlda;
}
 */ 
void sql_error()  
{  
    /* 显示SQL错误信息 */  
    printf("%.*s\n" , sqlca.sqlerrm.sqlerrml , sqlca.sqlerrm.sqlerrmc);  
}  
  
void alloc_descriptors(int size , int max_vname_len , int max_iname_len)  
{  
      
    int i;  
  
    /* 分配绑定描述区和选择描述区 */  
    bind_dp = SQLSQLDAAlloc(0 , size , MAX_VNAME_LEN , MAX_INAME_LEN);  
    select_dp = SQLSQLDAAlloc(0 , size , MAX_VNAME_LEN , MAX_INAME_LEN);  
  
  
    /* 为指示变量、绑定变量和选择列表项分配内存 */  
    for(i = 0 ; i != MAX_ITEMS ; ++i)  
    {  
        bind_dp->I[i] = (short*)malloc(sizeof(short));  
        select_dp->I[i] = (short*)malloc(sizeof(short));  
  
        bind_dp->V[i] = (char*)malloc(1);  
        select_dp->V[i] = (char*)malloc(1);  
    }  
}  
  
void dealloc_descriptors()  
{  
    int i;  
  
    /* 释放指示变量、绑定变量和选择列表项占用的内存 */  
    for(i = 0 ; i != MAX_ITEMS ; ++i)  
    {  
        if(bind_dp->V[i] != (char*)0)  
            free(bind_dp->V[i]);  
        free(bind_dp->I[i]);  
  
        if(select_dp->V[i] != (char*)0)  
            free(select_dp->V[i]);  
        free(select_dp->I[i]);  
    }  
  
    /* 释放绑定描述区和选择描述区 */  
    SQLSQLDAFree(0 , bind_dp);  
    SQLSQLDAFree(0 , select_dp);  
}  
  
void set_bind_variables()  
{  
    int i;  
    char bind_var[64];  
  
    /* 设置绑定变量最大个数 */  
    bind_dp->N = MAX_ITEMS;  
  
    /* 绑定变量名称: 绑定描述区 */  
    exec sql describe bind variables for s into bind_dp;  
  
    /* 设置绑定变量实际个数 */  
    bind_dp->N = bind_dp->F;  
  
    /* 循环处理绑定变量 */  
    for(i = 0 ; i != bind_dp->F ; ++i)  
    {  
        /* 显示绑定变量名 */  
        printf("请输入绑定变量%.*s的值:" , (int)bind_dp->C[i] , bind_dp->S[i]);  
  
        /* 输入绑定变量的值 */  
        gets(bind_var);  
  
        /* 设置绑定变量的长度成员 */  
        bind_dp->L[i] = strlen(bind_var);  
  
        /* 为绑定变量数据缓冲区重新分配内存(多一位,留给‘\0‘) */  
        bind_dp->V[i] = (char*)realloc(bind_dp->V[i] , bind_dp->L[i] + 1);  
  
        /* 绑定变量数据: 数据缓冲区 */  
        strcpy(bind_dp->V[i] , bind_var);  
  
        /* 设置指示变量,处理NULL */  
        if(0 == strncmp(bind_var , "NULL" , 4) || 0 == strncmp(bind_var , "null" , 4))  
            *bind_dp->I[i] = -1;  
        else  
            *bind_dp->I[i] = 0;  
  
        /* 设置数据缓冲区数据类型代码->char */  
        bind_dp->T[i] = 1;  
    }  
}  
  
void process_select_list()  
{  
    int i , null_ok , precision , scale;  
    char title[MAX_VNAME_LEN];  
  
    /* 设置选择列表项的最大个数 */  
    select_dp->N = MAX_ITEMS;  
  
    /* 选择列表项: 选择描述区 */  
    exec sql describe select list for s into select_dp;  
  
    /* 设置选择列表项的实际个数 */  
    select_dp->N = select_dp->F;  
  
    /* 循环处理选择列表项 */  
    for(i = 0 ; i != select_dp->F ; ++i)  
    {  
        /* 清除select_dp->T[i]的高位->null */  
        SQLColumnNullCheck(0 , (unsigned short*)&select_dp->T[i]  
            , (unsigned short*)&select_dp->T[i] , &null_ok);  
  
        /* 根据内部数据类型确定外部类型数据长度(显示长度) */  
        switch(select_dp->T[i])  
        {  
        case 2:  
            /* number类型,取得精度与标度 */  
            //SQLNumberPrecV6(0 , (unsigned short*)&select_dp->T[i] , &precision , &scale); 
            SQLNumberPrecV6(0 , (unsigned long *)&select_dp->L[i] , &precision , &scale);  //wangbaoming modify 201409
			
            if(scale > 0)  
                /* 实数: 显示长度:float  */  
                select_dp->L[i] = sizeof(float);  
            else  
                /* 整数: 显示长度 int */  
                select_dp->L[i] = sizeof(int);  
            break;  
        case 12:  
            /* DATA数据类型(DD-MON-YY) */  
            select_dp->L[i] = 9;  
            break;  
        }  
  
        /* 根据变量长度,重新为选择列表项数据缓冲区分配内存 */  
        if(2 != select_dp->T[i])  
            /* 其他类型 */  
            select_dp->V[i] = (char*)realloc(select_dp->V[i] , select_dp->L[i] + 1);  
        else  
            /* number类型 */  
            select_dp->V[i] = (char*)realloc(select_dp->V[i] , select_dp->L[i]);  
  
        /* 初始化title */  
        memset(title , ‘ ‘ , MAX_VNAME_LEN);  
  
        /* 选择列表项名称: title */  
        strncpy(title , select_dp->S[i] , select_dp->C[i]);  
  
        /* 显示列名 */  
        if(2 == select_dp->T[i])  
            if(scale > 0)  
                printf("\t%.*s" , select_dp->L[i] + 3, title);  
            else  
                printf("\t%.*s" , select_dp->L[i] , title);  
        else  
            printf("\t%-.*s" , select_dp->L[i] , title);  
  
        /* 根据Oracle内部类型确定外部数据类型(显示类型) */  
        if( 2 == select_dp->T[i])  
        {  
            /* number 类型*/  
            if(scale > 0)  
                /* float */  
                select_dp->T[i] = 4;  
            else  
                /* int */  
                select_dp->T[i] = 3;  
        }  
        else  
            /* char */  
            select_dp->T[i] = 1;  
    }  
  
    printf("\n");  
  
    /* 提取数据完毕->结束循环 */  
    exec sql whenever not found do break;  
  
    /* 循环处理选择列表数据 */  
    for( ; ; )  
    {  
        /* 数据->选择描述区 */  
        exec sql fetch c using descriptor select_dp;  
  
        /* 显示数据 */  
        for( i = 0 ; i != select_dp->F ; ++i)  
        {  
            if(*select_dp->I[i] < 0){  
                /* 处理NULL */  
                printf("\tNULL");  
            }else{  
                if(3 == select_dp->T[i]) {  
                    /* int */  
                    printf("\t%d" , *(int*)select_dp->V[i]);  
                }else if(4 == select_dp->T[i]){  
                    /* float */  
                    printf("\t%8.2f" , *(float*)select_dp->V[i]);  
                }else{  
                    /* char */  
                    printf("\t%.*s" , select_dp->L[i] , select_dp->V[i]);  
                }  
                }  
        }  
        printf("\n");  
    }  
}  


[oracle@oracle11 proc]$ 

编译脚本
[oracle@oracle11 proc]$ cat comp 
INCLUDE_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/
LD_PATH=/opt/oracle/app/product/11.2.0/dbhome_1/lib/
proc mode=oracle sqlcheck=full  main.pc
gcc main.c  -I$INCLUDE_PATH -L$LD_PATH -lclntsh  

开始编译:
[oracle@oracle11 proc]$ bash comp 
Pro*C/C++: Release 11.2.0.1.0 - Production on Mon Aug 29 19:49:55 2016

Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.

System default option values taken from: /opt/oracle/app/product/11.2.0/dbhome_1/precomp/admin/pcscfg.cfg

main.c:357: warning: conflicting types for ‘connect2’
main.c:190: note: previous implicit declaration of ‘connect2’ was here
main.c: In function ‘process_select_list’:
main.c:667: warning: passing argument 2 of ‘sqlprct’ from incompatible pointer type
/opt/oracle/app/product/11.2.0/dbhome_1/precomp/public/sqlcpr.h:88: note: expected ‘unsigned int *’ but argument is of type ‘long unsigned int *’
/tmp/cc7GfpD0.o: In function `main‘:
main.c:(.text+0x44): warning: the `gets‘ function is dangerous and should not be used.
[oracle@oracle11 proc]$ 

运行:
[oracle@oracle11 proc]$ ./a.out 
username:scott
password: 11
server:orcl
请输入动态SQL语句(exit:退出):select * from emp
	EMPN	ENAME     	JOB      	MGR 	HIREDATE 	SAL    	COMM   	DEPT
	7369	SMITH     	CLERK    	7902	17-DEC-80	  800.00	NULL	20
	7499	ALLEN     	SALESMAN 	7698	20-FEB-81	 1600.00	  300.00	30
	7521	WARD      	SALESMAN 	7698	22-FEB-81	 1250.00	  500.00	30
	7566	JONES     	MANAGER  	7839	02-APR-81	 2975.00	NULL	20
	7654	MARTIN    	SALESMAN 	7698	28-SEP-81	 1250.00	 1400.00	30
	7698	BLAKE     	MANAGER  	7839	01-MAY-81	 2850.00	NULL	30
	7782	CLARK     	MANAGER  	7839	09-JUN-81	 2450.00	NULL	10
	7788	SCOTT     	ANALYST  	7566	19-APR-87	 3000.00	NULL	20
	7839	KING      	PRESIDENT	NULL	17-NOV-81	 5000.00	NULL	10
	7844	TURNER    	SALESMAN 	7698	08-SEP-81	 1500.00	    0.00	30
	7876	ADAMS     	CLERK    	7788	23-MAY-87	 1100.00	NULL	20
	7900	JAMES     	CLERK    	7698	03-DEC-81	  950.00	NULL	30
	7902	FORD      	ANALYST  	7566	03-DEC-81	 3000.00	NULL	20
	7934	MILLER    	CLERK    	7782	23-JAN-82	 1300.00	NULL	10
请输入动态SQL语句(exit:退出):select * from student
	SID 	SNAME                         	ADDRESS                       	S	AGE 
	10	宋江                                            	梁山第一把交椅                             	M	40
	20	林冲                                            	豹子头                                         	M	30
	22	吴用                                            	智多星                                         	M	30
	23	鲁智深                                         	花和尚                                         	M	30
	21	燕青                                            	李师师                                         	M	23
	11	李逵                                            	黑旋风                                         	M	23
	12	王伦                                            	火并王伦                                      	M	33
	13	扈三娘                                         	王爱虎                                         	M	33
	14	高俅老二                                      	高衙内                                         	M	33
	15	西门庆                                         	潘金莲                                         	M	33
	16	镇关西                                         	卖猪肉                                         	M	33
请输入动态SQL语句(exit:退出):exit 
谢谢使用Oracle动态SQL方法四!

[oracle@oracle11 proc]$



本文出自 “魂斗罗” 博客,谢绝转载!

数据库编程4 Oracle Pro*C/C++开发