Proc/C++开发

Proc/C++开发

基本概念

  • SQL

    结构化查询语言,简称SQL,是一种数据库查询和程序设计语言,用于存取数据以及查询,更新和管理关系数据库系统;同时,也是数据库脚本文件的扩展名。

  • Pro*C/C++

    在C/C++程序中嵌入SQL语句操作数据库,得到的应用程序叫做Proc*C/C++程序。

  • 嵌入式SQL

    能在其它编程语言中混合使用的SQL语句,叫做嵌入式SQL语句!但是各个厂商对嵌入式SQL的具体实现不一样,但是具体的混合语法不一样,各厂商有自己的预编译工具。

  • 宿主语言

    嵌入式SQL的载体是宿主语言,比如这里说的就是C/C++。

宿主语言 Pro程序
C/C++ Pro*C/C++
FORTRAN Pro*FORTRAN
PASCAL Pro*PASCAL
COBOL Pro*COBOL
PL/I Pro*PL/I
Ada Pro*Ada

程序结构

  1. Include 头文件(c/c++ and Pro*c/c++)
  2. 定义变量
  3. 定义函数
  4. main
    4.1 连接数据库 :connect
    4.2 SQL操作语句:EXEC SQL …..
    4.3 exception handle
    4.4 断开连接
    4.5 EXEC SQL COMMIT / ROLLBACK WORK release

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sqlca.h"
EXEC SQL BEGIN DECLARE SECTION
char username[32];
char passwd[32];
char dname[25];
EXEC SQL END DECLARE SECTION
EXEC SQL INCLUDE sqlca;
void sqlerror();
void main(){
EXEC SQL WHENEVER SQLERROR DO sqlerror();
strcpy(username, "scott");
strcpy(passwd, "XXXXX");
EXEC SQL CONNECT :username IDENTIFIED BY :passwd;
EXEC SQL select 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);
}

开发流程

  1. 一般应用程序c开发运行标准流程

  2. 一般应用程序c++开发运行标准流程

Pro*C/C++ 应用程序的开发多了一个预编译的过程:pc转换成c或cpp文件

关于预编译工具(Proc)

  1. 位置:$ORACLE_HOME/bin 目录下拥有数据库访问权限的用户可以直接在终端使用,不需要绝对路径。
  2. 配置文件:$ORACLE_HOME/precomp/admin/pcscfg.cfg 头文件,库文件路径。
  3. 基本命令格式:proc iname=filename oname=outname [OptionName1=value1]…[OptionNameN=valueN]
  4. 基本选项:
选项 说明
INAME path and filename (name of input file) 1.pc
ONAME path and filename (name of output file) 1.c
INCLUDE path (头文件所在路径) -INCLUDE 路径名 或 INCLUDE= (路径名1,路径名2)
PARSE FULL 、PARTIA、NONE (DEFAULT FULL for C,Others for C++)
CODE ANSI_C、CPP (default ansi_c)
USERID username/password

默认预编译得到的是C文件,使用下列选项得到C++文件
parse=none 告诉proc编译器,按照C++规范解析 dm02_hello.pc
code = cpp 告诉proc编译器,按照C++规范生成文件
proc dm02_hello.pc parse=none code=cpp oname=dm02_hello.cpp

相关操作

  1. 连接数据库

    • 方法一
      EXEC SQL CONNECT :usr_pwd
    • 方法二
      EXEC SQL CONNECT :username IDENTIFIED BY :passwd
    • 方法三
      通过db_name连接没有限定名字的数据库–可以修改数据库的名字–at选项
      EXEC SQL CONNECT :username IDENTIFIED BY :passwd AT :db_name USING :db_string
  2. 代码里写死了用户名和密码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "sqlca.h"
    //定义宿主变量(SQL变量)
    //C语言可以直接使用
    //嵌入式SQL语句里面使用的话需要加上EXEC SQL前缀
    EXEC SQL BEGIN DECLARE SECTION;
    char * serverid = "scott/lzj123529";
    EXEC SQL END DECLARE SECTION;
    int main()
    {
    int ret = 0;
    printf("HelloWorld\n");
    EXEC SQL connect:serverid;
    if(sqlca.sqlcode != 0)
    {
    ret = sqlca.sqlcode ;
    printf("ret :%d\n",ret);
    return ret;
    }
    printf("connect OK!\n");
    EXEC SQL COMMIT RELEASE;//提交事务并且断开
    return 0;
    }
  3. 交互式的连接数据库

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    EXEC SQL BEGIN DECLARE SECTION;
    char user[32];
    char passwd[32];
    char sid[32];
    EXEC SQL END DECLARE SECTION;
    int main()
    {
    int ret = 0;
    printf("user:");
    scanf("%s",user);
    printf("passwd:");
    scanf("%s",passwd);
    printf("sid:");
    scanf("%s",sid);
    EXEC SQL CONNECT :user IDENTIFIED BY :passwd USING :sid;
    if(sqlca.sqlcode != 0)
    {
    ret = sqlca.sqlcode ;
    printf("ret :%d\n",ret);
    return ret;
    }
    printf("connect OK!\n");
    EXEC SQL COMMIT RELEASE;//提交事务并且断开
    return 0;
    }
  4. 通过宿主变量指定连接名字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//演示通过程序连接多个数据库
EXEC SQL BEGIN DECLARE SECTION;
char *usrname = "scott";
char *passwd = "tiger";
char *link1 = "link1"; //通过宿主变量指定连接名字
char *serverid = "orcl";
char *usrname2 = "scott";
char *passwd2 = "tiger";
char *link2 = "link2";
char *serverid2 = "orcl";
EXEC SQL END DECLARE SECTION;
int main()
{
int ret = 0;
//第一个用户连接数据库
EXEC SQL CONNECT :usrname IDENTIFIED BY :passwd AT :link1 USING :serverid ;
if (sqlca.sqlcode != 0)
{
ret = sqlca.sqlcode;
printf("第一个用户连接数据库 失败sqlca.sqlcode: err:%d \n", sqlca.sqlcode);
return ret;
}
else
{
printf("第一个用户连接数据库 成功connect ok...\n");
}
//第二个用户连接数据库
EXEC SQL CONNECT:usrname2 IDENTIFIED BY:passwd2 AT:link2 USING:serverid2 ;
if (sqlca.sqlcode != 0)
{
ret = sqlca.sqlcode;
printf("第二个用户连接数据库 失败sqlca.sqlcode: err:%d \n", sqlca.sqlcode);
return ret;
}
else
{
printf("第二个用户连接数据库 成功connect ok...\n");
}
//断开连接
EXEC SQL AT:link1 COMMIT RELEASE;
if (sqlca.sqlcode != 0)
{
ret = sqlca.sqlcode;
printf("第1个用户断开数据库 失败sqlca.sqlcode: err:%d \n", sqlca.sqlcode);
return ret;
}
else
{
printf("第1个用户断开数据库 成功 RELEASE ok...\n");
}
EXEC SQL AT:link2 COMMIT RELEASE;
if (sqlca.sqlcode != 0)
{
ret = sqlca.sqlcode;
printf("第二个用户断开数据库 失败sqlca.sqlcode: err:%d \n", sqlca.sqlcode);
return ret;
}
else
{
printf("第二个用户断开数据库 成功 RELEASE ok...\n");
}
return ret ;
}
  1. 宿主变量

C的数据类型不同于Oracle的数据类型,在数据传递时有一个数据类型转换过程。
在Proc*C/C++程序中,是被C和SQL语句使用的变量,位于

1
2
3
EXEC SQL BEGIN DECLARE SECTION
.............
EXEC SQL END DECLARE SECTION

之内。

主要类型:

程序中形式 说明
char 单字符
char[N] N个定长字符数组
short 短整型
long 长整型
float 单精度浮点数
double 双精度浮点数
VARCHAR[N] 变长字符串

使用场景

  • 输入:将应用程序的数据传递到数据库中
1
2
3
4
int salary,emp_number;
cin>>salary;
cin>>emp_number;
EXEC SQL update emp set sal= :salary where empno= :emp_number;
  • 输出:将数据库的数据传递到应用程序中。
1
2
3
4
float v_salary;
char v_job;
EXEC SQL select sal,job INTO :v_salary, :v_job from emp where empno=90;
cout<< v_salary<<v_job;
  • 申明语法与普通C变量一致,但在CODE=CPP或MODE=ANSI时变量必须放在申明区。
  • 可使用Pointer作为宿主变量,使用前分配空间。
  • 在数据定义语言(DDL)语句中不能用宿主变量。错误例子:
1
2
3
char table_name[30];
cin>> table_name;
EXEC SQL DROP TABLE :table_name
  1. 关于数据的增删改查

预先定义了

1
2
3
4
5
EXEC SQL BEGIN DECLARE SECTION;
int deptid = 50;
char dname[32] = "20name";
char loc[32] = "20loc";
EXEC SQL END DECLARE SECTION;

  • 插入数据
EXEC SQL insert into dept(DEPTNO,DNAME,LOC) values(:deptid,:dname,:loc);
  • 删除数据
EXEC SQL delete from dept where deptno=:deptid;
  • 修改数据
EXEC SQL update dept set loc = :loc where deptno=:deptid;

综合示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "sqlca.h"
//定义宿主变量(SQL变量)
//C语言可以直接使用
//嵌入式SQL语句里面使用的话需要加上EXEC SQL前缀
EXEC SQL BEGIN DECLARE SECTION;
//char * serverid = "scott/lzj123529";
char user[32];
char passwd[32];
char sid[32];
int deptid = 50;
char dname[32] = "20name";
char loc[32] = "20loc";
EXEC SQL END DECLARE SECTION;
int main()
{
int ret = 0;
printf("HelloWorld\n");
printf("\nuser:");
scanf("%s",user);
printf("\npasswd:");
scanf("%s",passwd);
printf("sid:");
scanf("%s",sid);
EXEC SQL CONNECT:user IDENTIFIED BY:passwd USING:sid;
if(sqlca.sqlcode != 0)
{
ret = sqlca.sqlcode ;
printf("ret :%d\n",ret);
return ret;
}
printf("connect OK!\n");
EXEC SQL insert into dept(DEPTNO,DNAME,LOC) values(:deptid,:dname,:loc);
EXEC SQL COMMIT;//提交事务不退出
sleep(10);
printf("delete ....\n");
//EXEC SQL delete from dept where deptno=:deptid;
strcpy(loc,"中国");
EXEC SQL update dept set loc = :loc where deptno=:deptid;
EXEC SQL COMMIT RELEASE;//提交事务并且断开
return 0;
}