Proc *C/C++入门--C/C++操作Oracle数据库

Proc *C/C++入门

有点累啊 整理笔记!!!

基本概念

  • SQL
    构化查询语言(Structured Query Language)简称SQL,是一种数据库查询和程序设计语言,用于存取数据以及查询、更新和管理关系数据库系统;同时也是数据库脚本文件的扩展名。
    1986年10 月由美国国家标准局(ANSI)通过的数据库语言美国标准,接着,国际标准化组织(ISO)颁布了SQL正式国际标准。

  • Pro*C/C++
    在C/C++程序中嵌入SQL语句操作数据库,得到的应用程序叫做Proc*C/C++程序!优点是高效!

  • 嵌入式SQL

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

SQL86(1986年发布)中定义了对于COBOL, FORTRAN, PI/L等语言的嵌入式SQL的规范。在SQL89(1989年发布)规范中,定义了对于C语言的嵌入式SQL的规范。

  • 宿主语言
    嵌入式SQL的载体是宿主语言,比如这里说的就是C/C++!
宿主语言Pro程序
C/C++Pro*C/C++
FORTRANPro*FORTRAN
PASCALPro*PASCAL
COBOLPro*COBOL
PL/IPro*PL/I
AdaPro*Ada
  • 访问数据库的方法
    • 命令行:Sql*Plus
    • web界面:Enterprise Manager Console(在数据库主机开启一个服务器供B/S架构使用)
    • 第三方应用程序:自己开发的程序,可用C/C++或者Java(JDBC)

  • 程序结构

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

#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,“scott");
   strcpy(password, “*****");
   EXEC SQL CONNECT:username IDENTIFIED BY:password;
   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);
}

开发流程

  • 流程比较

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

  • 关于预编译工具–Proc
    • 位置:$ORACLE_HOME/bin目录下–拥有数据库访问权限的用户可以直接在终端使用,不需要绝对路径
    • 配置文件:$ORACLE_HOME/precomp/admin/pcscfg.cfg –头文件、库文件路径
    • 基本命令格式:proc iname=filename oname=outname [OptionName1=value1]…[OptionNameN=valueN](C++)或者直接proc xxx.pc
    • 基本选项:
选项说明
INAMEpath and filename (name of the input file) 1.pc
ONAMEpath and filename (name of the output file) 1.c 1.cc
INCLUDEpath (头文件所在路径)–INCLUDE 路径名 或 INCLUDE =(路径名1,路径名2)
PARSEFULL 、 PARTIA 、 NONE (default FULL for C, Others for C++)
CODEANSI_C 、 CPP (default ansi_c)
USERIDusername/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.cc
  • 结合命令简述开发流程:
    1. vim hello.pc
    2. proc hello.pc
    3. gcc -g hello.c -o app -I ORACLEHOME/precomp/publicL {ORACLE_HOME}/lib -lclntsh
    4. ./app [args]
#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()
{

    printf("HelloWorld\n");
    return 0;
}
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "sqlca.h"
using namespace std;

EXEC SQL BEGIN DECLARE SECTION;
char * serverid = "scott/lzj123529";
EXEC SQL END DECLARE SECTION;

int main()
{

    cout<<"HelloWorld\n";
    return 0;
}

相关基础语法

连接数据库

用到的嵌入式SQL语句:

EXEC SQL CONNECT { :user IDENTIFIED BY :oldpswd | :usr_psw }
   [[ AT { dbname | :host_variable }] USING :connect_string ]
      [ {ALTER AUTHORIZATION :newpswd  |  IN { SYSDBA | SYSOPER } MODE} ] ;

连接之前开始lsnrctl以及启动数据库服务

  • 方法1
    EXEC SQL CONNECT :usr_pwd;

  • 方法2
    EXEC SQL CONNECT :username IDENTIFIED BY :password ;

  • 方法3
    通过db_name连接没有限定名字的数据库–可以修改数据库的名字–at选项 */
    EXEC SQL CONNECT :username IDENTIFIED BY :password AT :db_name USING :db_string;

/* declare needed host variables */
char  username[10]  = "scott"; 
char  password[10]  = "tiger";
char  db_string[20] = "NYNON"; 

/* give the database connection a unique name */ 
EXEC SQL DECLARE DB_NAME DATABASE; 

/* connect to the nondefault database  */
EXEC SQL CONNECT :username IDENTIFIED BY :password 
   AT DB_NAME USING :db_string;

1.代码里写死了用户名和密码

#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;
}

2.交互式的连接数据库

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;
}

3.连接多个数据库

3.1 通过宿主变量指定连接名字

//演示通过程序连接多个数据库
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 ;
}

3.2 通过系统分配方式指定连接名字

EXEC SQL BEGIN DECLARE SECTION;
    char        *usrname = "myscott";
    char        *passwd = "22";
    //char      *link1 = "link1";
    char        *serverid = "orcl";

    char        *usrname2 = "myscott";
    char        *passwd2 = "22";
    //char      *link2 = "link2";
    char        *serverid2 = "orcl";
EXEC SQL END DECLARE SECTION;

int main()
{
    int ret = 0;    
    //使用oracle声明连接 EXEC SQL DECLARE link1 DATABASE; 
    EXEC SQL DECLARE link1 DATABASE; 
    EXEC SQL DECLARE link2 DATABASE; 

    //第一个用户连接数据库
    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("第2个用户断开数据库 失败sqlca.sqlcode: err:%d \n", sqlca.sqlcode);
        return ret;
    }
    else
    {
        printf("第2个用户断开数据库 成功 RELEASE ok...\n");
    }
    return ret ;
}

宿主变量

C 的数据类型不同于ORACLE的数据类型,在数据传递时有一个数据类型转换的过程。

在Proc*C/C++程序中,能通是被C和SQL语句使用的变量!位于

EXEC SQL BEGIN DECLARE SECTION;
    ... ...
EXEC SQL END DECLARE SECTION;

之内!!

主要类型:

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

使用场景:

1.输入 — 将应用程序的数据传递到数据库中。

nt salary, emp_number;
cin>>salary; cin>>emp_number;
EXEC SQL update emp set sal=:salary where empno= :emp_number;

2.输出 — 将数据库的数据传递到应用程序中。

float v_salary;
char v_job;
EXEC SQL select sal,job INTO :v_salary, :v_job from emp where empno = 7788;
cout<<v_salary<<v_job;

3.申明语法与普通C变量一致,但在CODE=CPP或 MODE=ANSI时变量必须放在申明区.

4.可使用pointer 作为宿主变量,使用前分配空间。

5.在DDL语句中不能用宿主变量。错误例子:

char table_name[30];
cin>>table_name;
EXEC SQL DROP TABLE :table_name;

6.预编译选项 CHAR_MAP

CHAR_MAP=CHARZ (默认设置): ‘\0’结尾,定长,空格补齐。
CHAR_MAP=CHARF | VARCHAR2:定长,空格补齐。
CHAR_MAP=STRING:     ‘\0’结尾,变长。

7.当‘\0’结尾,宿主变量长度要大于实际数据长度。
8.VARCHAR
* 变长, 不是‘\0’结尾。
* 结构体类型

    Struct{
        unsigned short len;
        unsigned char arr[ ]
    }variable_name;

数据类型

1.内部类型

就是在Sql*Plus使用到的数据类型!

Oracle数据就是Oracle数据库内部使用的数据类型:

类型说明
VARCHAR2变长字符串,最大4000字节
CHAR定长字符串,最大2000字节
NUMBER(p,s)数字类型,p精度,s标度
DATE日期时间数据,7字节
RAW变长二进制数据,最大2000字节
LONG大批量数据,最大2G字节
LONG RAW大二进制数据,最大2G字节
CLOB大批量字符数据,最大4G
BLOB大批量二进制数据,最大4G
BFILEOS文件数据
NCHAR,NVARCHAR2,NCLOB本地字符集数据
ROWID伪列——表行物理地址

数据库中的表和伪列使用这些数据类型

2.外部类型

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定长字符
CHARZNULL终止定长字符串
CHARF等价CHAR的字符数据类型
MLSLABEL操作系统标记

外部数据类型包括全部的内部数据类型和宿主语言中所提供的几个数据类型

3.宿主类型
宿主变量数据类型也是SQL数据类型

  • Oracle的外部数据类型与宿主变量的自动类型转换

  • Oracle的外部数据类型与宿主变量的人工类型转换

1.

EXEC SQL VAR host_variable IS type_name[(length)];
        char  emp_name[11];
        EXEC SQL VAR emp_name IS STRING(11);

2.用户定义类型等价

EXEC SQL TYPE user_type IS type_name[(length)];
typedef struct {
    short  len;
    char   buff[4000];
} graphics;
EXEC SQL TYPE graphics IS VARRAW(4000);

3.TO_DATE

例子:
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 = "22";
    char    *serverid = "orcl";

    int             deptno;
    dnameType       dname;
    short           dname_ind;
    locType         loc;
    short           loc_ind;    
EXEC SQL END DECLARE SECTION;

EXEC SQL BEGIN DECLARE SECTION;
    char    *usrname = "scott";
    char    *passwd = "tiger";
    char    *serverid = "orcl";

    int         count;

    int         deptno[100];
    char        dname[100][20];
    char        loc[100][20];

    int         deptno2[100];
    varchar     dname2[100][20]; //varchar类型 和 char 类型的区别
    varchar     loc2[100][20];

EXEC SQL END DECLARE SECTION;

关于数据的增删改查

预先定义了

EXEC SQL BEGIN DECLARE SECTION;

int deptid = 50;
char dname[32] = "20name";
char loc[32] = "20loc";

EXEC SQL END DECLARE SECTION;

1.插入数据

EXEC SQL insert into dept(DEPTNO,DNAME,LOC) values(:deptid,:dname,:loc);

2.删除数据

EXEC SQL delete from dept where deptno=:deptid;

3.修改数据

EXEC SQL update dept set loc = :loc where deptno=:deptid;

综合实例:

#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;
}

错误处理机制




EXEC SQL WHENEVER <condition> <aciton>
condition:
    SQLWARNING
    SQLERROR
    NOT FOUND   编译选项    MODE=ORACLE sqlca.sqlcode = 1403 
                编译选项    MODE=ANSI   sqlca.sqlcode = 100
aciton:
    CONTINUE
    DO
    GOTO label_name
    STOP
EXEC SQL WHENEVER SQLERROR GOTO connect_error; 
... 
connect_error: 
    EXEC SQL WHENEVER SQLERROR CONTINUE; 
    EXEC SQL ROLLBACK RELEASE; 
    printf("\nInvalid username/password\n"); 
    exit(1); 

完整示例:

#include <stdio.h>
#include  <string.h>
#include <stdlib.h>

#include "sqlca.h"

//连接数据

//先定义宿主变量 (SQL变量)
EXEC SQL BEGIN  DECLARE SECTION ;
    char * serverid = "scott/tiger2@orcl";
    int     deptid;
    char    DNAME[32];
    char    LOC[32];

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;
    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; 
}


遇到的错误

  1. 找不到头文件stddef.h
$ locate stddef.h

把对应的头文件路径添加到Proc的配置文件(pcscfg.cfg)里面

  1. 看错误代码的含义:
$ oerr ora 错误码
  • 1
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值