当前位置: 首页 > 工具软件 > Pro*C > 使用案例 >

proc*c/c++简介

亢正德
2023-12-01

一、概述

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和输出缓冲区中,以供用户使用

 

 

 类似资料: