一、概述
1. 概念
通过在过程化编程语言C/C++中嵌入SQL语句而开发出的应用程序。在通用编程语言中使用的SQL称为嵌入式SQL。
在SQL标准中定义了多种语言的嵌入式SQL ,各个厂商对嵌入式SQL的具体实现不同。
在C/C++语言中嵌入SQL语句而开发出的应用程序称为Pro*C/C++程序。
目的:使c/c++这种高效率语言成为访问数据库的工具。
嵌入式SQL的载体是宿主语言。
宿主语言 Pro程序
C/C++ Pro*C/C++
FORTRAN Pro*FORTRAN
PASCAL Pro*PASCAL
访问数据库的方法
用SQL*Plus, 它有SQL命令以交互的应用程序访问数据库;
用第四代语言应用开发工具开发的应用程序访问数据库,这些工具有SQL*Froms,QL*Reportwriter,SQL*Menu等;
利用在第三代语言内嵌入的SQL语言或ORACLE库函数调用来访问。
访问oracle数据库的方法
SQLPLUS oracle自带访问数据库工具
JDBC java database connectivity standard
ODBC open database connectivity开放数据库互连
OCI oracle call interface
OCCI oracle c++ call interface
Pro*X Pro*C/C++ Pro*COBOL等
2. 程序结构
Pro*C程序实例
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sqlca.h"
EXEC SQL BEGIN DECLARE SECTION;
char username[32];
char password[32];
char dname[25];
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE sqlca;
void sqlerror();
main()
{
EXEC SQL WHENEVER SQLERROR DO sqlerror();
strcpy(username,“haha");
strcpy(password, “haha");
EXEC SQL CONNECT:username IDENTIFIED BY:password;
EXEC SQL select dname into :dname from dept where id=10;
printf(“dname:%s \n”, dname);
}
void sqlerror()
{
EXEC SQL WHENEVER SQLERROR CONTINUE;
printf("\n---- oracle error detected:\n");
printf("%.70s\n", sqlca.sqlerrm.sqlerrmc);
EXEC SQL ROLLBACK WORK RELEASE;
exit(1);
}
Pro*C程序结构
Include 头文件 (c/c++ and pro*c/c++)
定义变量
定义函数
main
连结数据库: connect
SQL 操作语句: EXEC SQL …….;
exception handler
断开连结:
EXEC SQL COMMIT / ROLLBACK WORK release
3. 开发流程
需要使用proc将.pc文件预编译为.c文件,再按照.c文件的流程编译.c文件。
例子
编写hello.pc
#include <stdio.h>
#include <string.h>
#include "sqlca.h"
EXEC SQL BEGIN DECLARE SECTION ;
char *serverid = "scott/123456@orcl";
EXEC SQL END DECLARE SECTION;
int main()
{
int ret = 0;
printf("hello...\n");
printf("serverid:%s\n", serverid);
EXEC SQL connect :serverid;
if(sqlca.sqlcode != 0)
{
ret = sqlca.sqlcode;
printf("EXEC SQL connect:err, %d\n", ret);
return ret;
}
printf("connect ok\n");
return ret;
}
使用proc命令proc hello.pc
使用gcc命令
gcc hello.c -I/home/oracle_11/app/oracle/product/11.2.0/db_1/precomp/public -L//home/oracle_11/app/oracle/product/11.2.0/db_1/lib -lclntsh
c++例子
编写c++版的hellocpp.pc
#include <stdio.h>
#include <string.h>
#include "sqlca.h"
using namespace std;
EXEC SQL BEGIN DECLARE SECTION ;
char *serverid = "scott/123456@orcl";
EXEC SQL END DECLARE SECTION;
int main()
{
int ret = 0;
cout << "hello...\n" << endl;
cout << "serverid:" << serverid << endl;
EXEC SQL connect :serverid;
if(sqlca.sqlcode != 0)
{
ret = sqlca.sqlcode;
printf("EXEC SQL connect:err, %d\n", ret);
return ret;
}
printf("connect ok\n");
return ret;
}
使用proc编译
proc iname=C:\Users\Administrator\Desktop\hellocpp.pc oname= C:\Users\Administrator\Desktop\hellocpp.cc PARSE=NONE CODE=CPP
使用g++编译
g++ hellocpp.cc -I/home/oracle_11/app/oracle/product/11.2.0/db_1/precomp/public -L//home/oracle_11/app/oracle/product/11.2.0/db_1/lib -lclntsh
二、prc*c/c++基础开发
1. 连接数据库
见上面的例子。
2. 宿主变量和指示器变量
宿主变量是一种pro*c语言变量, 用于在应用程序中和oracle数据库之间传递数据。Pro*C程序中,既可在SQL语句中引用,也可在C语句中引用的变量称为SQL变量。
宿主变量的数据类型
char 单字符
char[n] N个定长字符数组
int 整数
Short 短整数
long 长整数
float 单精度浮点数
double 双精度浮点数
VARCHAR[n] 变长字符串
例子
编写demo1.pc
#include <stdio.h>
#include <string.h>
#include "sqlca.h"
EXEC SQL BEGIN DECLARE SECTION ;
char *serverid = "scott/123456@orcl";
int tid;
char tname[20];
char taddress[50];
int tid2;
char tname2[20];
char taddress2[50];
EXEC SQL END DECLARE SECTION;
int main()
{
int ret = 0;
printf("hello...\n");
printf("serverid:%s\n", serverid);
EXEC SQL connect :serverid;
if(sqlca.sqlcode != 0)
{
ret = sqlca.sqlcode;
printf("EXEC SQL connect:err, %d\n", ret);
return ret;
}
printf("connect ok\n");
tid = 1;
EXEC SQL select tid, tname, taddress into :tid2, :tname2, :taddress2 from t1 where tid=:tid;
printf("%d, %s, %s\n", tid, tname, taddress);
tid = 100;
strcpy(tname, "test1");
strcpy(taddress, "beij");
EXEC SQL insert into t1 (tid, tname, taddress) values (:tid, :tname, :taddress);
EXEC SQL COMMIT;
strcpy(taddress, "shangh");
EXEC SQL update t1 set taddress=:taddress where tid=:tid;
EXEC COMMIT;
EXEC SQL delete from t1 where tid=:tid;
EXEC SQL COMMIT RELEASE;
return ret;
}
指示变量(indicator variable)
短整型变量,用于处理数据库的NULL值,监督和管理与其相关联的宿主变量。
引用语法:
:host_variable INDICATOR :indicator_variable
OR
:host_variable:indicator_variable
主要用在输出, 即当宿主变量用于接收数据库的返回数据时.
通过在宿主变量后用指示变量, 检测是否返回了NULL.
-1:数据库表列的值为NULL,指示变量相关联的输出宿主变量值不确定
=0:Oracle将数据库表列值原封不动的赋给指示器变量相关联的输出宿主变量
>0: Oracle将数据库表列值截断后赋给指示器变量相关联的输出宿主变量,指示器变量值为该列值的原始长度
例子:
#include <stdio.h>
#include <string.h>
#include "sqlca.h"
typedef char danmeType[20];
typedef char locType[20];
EXEC SQL BEGIN DECLARE SECTION;
char *serverid = "scott/1234@orcl";
int deptno;
int dname[20];
short dname_ind;
char loc[20];
short loc_ind;
int deptno2;
int dname2[20];
char loc2[20];
EXEC SQL END DECLARE SECTION;
int main()
{
int ret = 0;
EXEC SQL connect :serverid;
if(sqlca.sqlcode != 0)
{
ret = sqlca.sqlcode;
printf("EXEC SQL connect:err, %d\n", ret);
return ret;
}
printf("connect ok\n");
deptno2 = 10;
EXEC SQL select deptno, dname, loc into :deptno2, :dname2, :loc2:loc_ind from dept where deptno2=:deptno;
if(loc_ind == -1)
{
printf("loc2 is null\n");
strcpy(loc2, "null");
}
deptno = 20;
strcpy(dname, "sale");
strcpy(loc, "bj");
printf("%d, %s, %s\n", deptno2, dname2, loc2);
loc_ind = -1;
EXEC SQL insert into dept (deptno, dname, loc) values (:deptno, :dname, :loc:loc_ind);
EXEC SQL COMMIT RELEASE;
}
3. oracle数据类型
宿主变量可以被sql语言使用也可以被C语言使用.
C 的数据类型不同于ORACLE的数据类型,在数据传递时有一个数据类型转换的过程。
Oracle数据就是Oracle数据库内部使用的数据类型:
VARCHAR2:变长字符串,最大4000字节
CHAR:定长字符串,最大2000字节
NUMBER(p,s) :数字类型,p精度,s标度
DATE:日期时间数据,7字节
RAW:变长二进制数据,最大2000字节
LONG:大批量数据,最大2G字节
LONG RAW:大二进制数据,最大2G字节
CLOB:大批量字符数据,最大4G
BLOB:大批量二进制数据,最大4G
BFILE:OS文件数据
NCHAR,NVARCHAR2,NCLOB:本地字符集数据
ROWID:伪列——表行物理地址
Oracle外部数据类型是宿主程序所引用的数据类型,在运行Pro*C/C++程序的时候,Oracle会根据需要将宿主变量的数据类型映射成Oracle外部数据类型,在编写Pro*C/C++程序的时候不能直接使用Oracle外部数据类型来定义宿主变量。
VARCHAR2:变长字符串
NUMBER:数字值
INTEGER:有符号整数
FLOAT:浮点数
STRING:以NULL终止的变长字符串
VARNUM:数字值,但包含数字长度
LONG:长字符串
VARCHAR:变长字符串
ROWID:二进制值
DATE:日期
VARRAW:变长二进制
RAW:定长二进制
LONG RAW:定长二进制
UNSIGNED:无符号整数
LONG VARCHAR:变长字符串
LONG VARRAW:变长二进制
CHAR:定长字符
CHARZ:NULL终止定长字符串
CHARF:等价CHAR的字符数据类型
MLSLABEL:操作系统标记
Oracle的外部数据类型与宿主变量的人工类型转换的3中方式:
EXEC SQL VAR host_variable IS type_name[(length)];
char emp_name[11];
EXEC SQL VAR emp_name IS STRING(11);
用户定义类型等价
EXEC SQL TYPE user_type IS type_name[(length)];
typedef struct {
short len;
char buff[4000];
} graphics;
EXEC SQL TYPE graphics IS VARRAW(4000);
TO_DATE
例子
EXEC SQL BEGIN DECLARE SECTION;
EXEC SQL TYPE dnameType is string(20);
EXEC SQL TYPE locType is string(20);
char *usrname = "scott";
char *passwd = "123";
char *serverid = "orcl";
int deptno;
dnameType dname;
short dname_ind;
locType loc;
short loc_ind;
EXEC SQL END DECLARE SECTION;
4. oracle通讯区和错误处理机制
SQLCA 是ORACLE提供的两个通信区之一。SQLCA实际上是一个结构变量,其目的是为了诊断错误和事件处理结果。
错误处理机制
当在pro*c/c++应用程序中运行sql语句时,oracle会将最近执行的sql语句的状态信息存储到状态变量sqlcode、sqlstate或sqlca结构中。当sql语句执行成功时,一般情况下不需要进行任何其他处理;当sql语句执行失败时,应用程序应该能够检测到失败信息,并进行适当的处理,以加强应用程序的健壮性。在编写pro*c/c++应用程序时,通过使用whenever语句可以检测并处理sql错误。
EXEC SQL WHENEVER <condition> <action>
其中,conditon用于指定要检测的条件,action用于指定满足特定条件时要执行的操作。
例子:
#include <stdio.h>
#include <string.h>
#include "sqlca.h"
typedef char danmeType[20];
typedef char locType[20];
EXEC SQL BEGIN DECLARE SECTION;
char *serverid = "scott/1234@orcl";
int deptno;
int dname[20];
short dname_ind;
char loc[20];
short loc_ind;
int deptno2;
int dname2[20];
char loc2[20];
EXEC SQL END DECLARE SECTION;
void sqlerr()
{
EXEC SQL WHENEVER SQLERROR CONTINUE;
printf("err reason:%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
EXEC SQL ROLLBACK WORK RELEASE;
exit(1);
}
int main()
{
int ret = 0;
EXEC SQL WHENEVER SQLERROR DO sqlerr();
EXEC SQL connect :serverid;
if(sqlca.sqlcode != 0)
{
ret = sqlca.sqlcode;
printf("EXEC SQL connect:err, %d\n", ret);
return ret;
}
printf("connect ok\n");
deptno2 = 10;
EXEC SQL select deptno, dname, loc into :deptno2, :dname2, :loc2:loc_ind from dept where deptno2=:deptno;
if(loc_ind == -1)
{
printf("loc2 is null\n");
strcpy(loc2, "null");
}
deptno = 20;
strcpy(dname, "sale");
strcpy(loc, "bj");
printf("%d, %s, %s\n", deptno2, dname2, loc2);
loc_ind = -1;
EXEC SQL insert into dept (deptno, dname, loc) values (:deptno, :dname, :loc:loc_ind);
EXEC SQL COMMIT RELEASE;
}
5. 宿主数组
例子
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sqlca.h"
//连接数据
void sqlerr();
void sqlerr2();
//先定义宿主变量 (SQL变量)
EXEC SQL BEGIN DECLARE SECTION ;
char * serverid = "scott/tiger@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 ;
//sqlerrd[2]SQL语句处理的行数,如果SQL执行失败,则没有定义
int main()
{
int ret = 0, i = 0;
int count;
printf("hello....\n");
EXEC SQL WHENEVER SQLERROR DO sqlerr();
EXEC SQL connect :serverid;
//EXEC SQL WHENEVER NOT FOUND CONTINUE;
EXEC SQL select deptno, dname, loc into :deptno2, :dname2, :loc2:loc_ind from dept ;
count= sqlca.sqlerrd[2];
printf("count: %d \n", count);
for (i=0; i<count; i++)
{
printf("%d, %s, %s\n", deptno2[i], dname2[i].arr, loc2[i].arr);
}
/*
// create + as
create table dept33
as
select * from dept where 1=2
*/
EXEC SQL FOR :count insert into dept33(deptno, dname, loc) values(:deptno2, :dname2, :loc2);
EXEC SQL COMMIT RELEASE; //提交事务断开连接
return ret;
}
//错误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);
}
6. 游标
使用游标,操作多行多列时,逐行或随机处理数据。
基本步骤
定义游标
EXEC SQL DECLARE emp_cursor CURSOR FOR
select empno,ename,sal from emp where deptno=10;
打开游标
EXEC SQL OPEN emp_cursor ;
(Open cursor: put the select results into a memory place, and the cursor pointer points to the first row data.)
提取数据 fetch into
EXEC SQL FETCH emp_cursor INTO :empnum,:name:salary;
/** 在此处理数据处理**/
(After fetch, cursor pointer moves down one line. Use loop for multiple rows)
关闭游标
EXEC SQL CLOSE emp_cursor;
例子
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 = "myscott";
char *passwd = "1234";
char *serverid = "orcl";
int deptno;
dnameType dname;
short dname_ind;
locType loc;
short loc_ind;
EXEC SQL END DECLARE SECTION;
int main01()
{
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 dept_cursor CURSOR FOR
select deptno, dname, loc from dept;
//2 打开游标 open cursor
EXEC SQL OPEN dept_cursor;
//3 获取数据 fetch data
EXEC SQL WHENEVER NOT FOUND DO break;
while (1)
{
EXEC SQL FETCH dept_cursor INTO :deptno, :dname:dname_ind, :loc:loc_ind;
printf("条目数:%d\t", sqlca.sqlerrd[2]);
printf("%d\t %s\t %s ", deptno, dname, loc );
if (dname_ind == -1)
{
printf("dname is null \t");
}
if (loc_ind == -1)
{
printf("loc is null \t");
}
printf("\n");
}
//4 关闭游标 close data
EXEC SQL CLOSE dept_cursor;
EXEC SQL COMMIT WORK RELEASE;
printf("return ok...\n");
return ret ;
}
void connect()
{
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", ret);
return ;
}
else
{
printf("connect ok ... \n");
}
}
滚动游标的例子
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sqlca.h"
extern sqlgls(char * , size_t *, size_t * );
extern sqlglmt(void *,char *,size_t *,size_t *);
void connet();
void sqlerr02();
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 ;
}
}
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 = "myscott";
char *passwd = "1234";
char *serverid = "orcl";
int deptno;
dnameType dname; //string 数据类型
short dname_ind;
locType loc;
short loc_ind;
EXEC SQL END DECLARE SECTION;
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 dept_cursor SCROLL CURSOR FOR
select deptno, dname, loc from dept;
//2 打开游标 open cursor
EXEC SQL OPEN dept_cursor;
//3 获取数据 fetch data
//while (1)
{
//EXEC SQL WHENEVER NOT FOUND DO break;
//查询最后一条数据
EXEC SQL FETCH LAST dept_cursor 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 dept_cursor 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 dept_cursor 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 dept_cursor 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 dept_cursor 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 dept_cursor 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 dept_cursor;
EXEC SQL COMMIT WORK RELEASE;
printf("return ok...\n");
return ret ;
}
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");
}
}
三、pro*c/c++动态sql
1. 概念
动态SQL是指在运行pro*c/c++应用程序时,动态输入的SQL语句。
目的:加强应用程序的功能和灵活性。
比较静态SQL和动态SQL:
静态SQL ---- 在编写应用程序时,使用EXEC SQL关键字直接嵌入的SQL语句;在proc编译应用程序生成c语言的时,都已经确定
动态SQL ---- 在运行应用程序时,由用户动态输入的SQL语句。
使用动态SQL语句的情形:
SQL语句的文本(命令,子句等)不确定
宿主变量个数不确定
宿主变量的数据类型不确定
引用的数据库对象(列,表等)不确定
2. 动态sql方法1
语法:EXEC SQL EXECUTE IMMEDIATE :host_string
host_string 字符串
限制性,要求是非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();
pSql = mySql;
//循环处理sql语言
for(;;)
{
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 ;
}
3. 动态sql2
使用PREPARE命令准备SQL语句
EXEC SQL PREPARE statement_name FROM :host_string;
statement_name: 标识符
host_string:含SQL语句的字符串
使用EXECUTE命令执行SQL语句
EXEC SQL EXECUTE statement_name [USING :host_variable]
如果SQL语句要通过宿主变量赋值,输入SQL语句时要用占位符
例子
int main02()
{
int ret = 0;
int i = 0;
char choosechar;
memset(mySql, 0, sizeof(mySql));
pSql = NULL;
EXEC SQL WHENEVER SQLERROR DO sqlerr02();
connet();
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 ;
}
4. 动态sql3
使用PREPARE命令准备SQL语句
EXEC SQL PREPARE statement_name FROM :host_string;
statement_name: 标识符,
host_string:含SQL语句的字符串
使用DECLARE命令定义游标
EXEC SQL DECLARE cursor_name CURSOR FOR statement_name;
EXEC SQL OPEN cursor_name [using host_variable_list]
EXEC SQL FETCH cursor_name INTO host_variable_list
EXEC SQL CLOSE cursor_name
例子
//可以结合游标一块使用
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语言
for(;;)
{
printf("\n请输入部门编号 ");
scanf("%d", &deptno);
//准备动态sql
EXEC SQL PREPARE my_pre_sql3 FROM 'select deptno, dname, loc from dept where deptno > :a';
//定义游标
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\t %s\t %s \n", deptno, dname, loc);
}
EXEC SQL CLOSE c1;
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 ;
}
5. 动态sql4
既适用于SELECT语句,也适用于非SELECT语句,但是,它与前面的方法相比有两个突出的不同点:
方法4的动态SQL语句不但包含选择表项或虚拟输入宿主变量,而且它们的个数或数据类型在编译时还不知道
在其它方法中,ORACLE和C之间的数据类型转换是自动实现的。而在方法4中,由于动态语句中的宿主变量个数和类型在编译时还不知道,因此不能实现自动转换,必须由程序来控制数据类型之间的转换
提供信息
选择表项和实输入宿主变量的个数
每一个选择表项和实输入宿主变量的成年高度
每一个选择表项和实输入宿主变量的数据类型
每一个输出宿主变量和实输入宿主变量的内存单元地址
SQLDA
为了保存执行动态SQL语句所需要的信息,系统提供一个称之为SQL描述区的程序数据结构。把ORACLE所需要的全部有关选择表项或虚拟输入宿主变量的信息,除了值和名字外,都存储在SQLDA中
SQLDA中所包含的信息主要通过以下三种方法写入:
sqlald()函数:在分配描述区和缓冲区的同时,还把SLI或P的名字在缓冲区中的地址和长度写入SQLDA中
应用程序:通过程序把SLI或BV值的缓冲区地址、长度既数据类型写入SQLDA
DESCRIBE语句:检查每一个选择表项,确定它的名字、数据类型、约束、长度、定标和精度,然后把这方面的信息存储在选择SQLDA和输出缓冲区中,以供用户使用