2009-04-23

C/C++调用OCCI方法全解析

    C/C++操作Oracle数据库的方式核心有两种:C的OCI与C++的OCCI,OCCI的语法近于 JDBC,简单易学,但OCI接口复杂,难以学习、理解和使用,因此Oracle提出了折中方案:Pro*C,在C语言文件里嵌入SQL语句,通过proc预编译产生包含OCI函数的C文件,但另外的麻烦又来了,预编译文件.pc,由于嵌入了SQL语句,并不符合C的语法,IDE会产生警告,自然,如果你习惯于使用vi来编辑,则令当别论了。如果在C源文件中直接使用OCCI的方法,使用C++编译器来编译所有的C文件,也是一种简化问题的方法,但将大量C文件使用C++编译器编译让人感觉不是那么痛快。
    如果能封装OCCI对数据库的操作,并生成C语言的动态库或静态库,那就可以继续使用C编译器来编译其他的源文件了,最终动态链接或通过连接器静态链接到一起就行了。

一、 C++的OCCI操作数据库
    要用C封装OCCI,首先是要知道如果用C++通过OCCI来操作数据库
/*
 * occi.h
 *
 *  Created on: Apr 22, 2009
 *      Author: hanchen
 */

#ifndef OCCI_H_
#define OCCI_H_

#include <occi.h>

using namespace std;
using namespace oracle::occi;

class OcciDemo {
private:
        Environment *env;
        Connection *conn;
public:
        OcciDemo(string user, string passwd, string dbname);
        ~OcciDemo();
        void displayTable();
};

#endif /* OCCI_H_ */


/*
 * occi.cpp
 *
 *  Created on: Apr 22, 2009
 *      Author: hanchen
 */

#include <iostream>
#include <algorithm>
#include "occi.h"

OcciDemo::OcciDemo(string user, string passwd, string dbname) {
        env = Environment::createEnvironment(Environment::OBJECT);
        conn = env->createConnection(user, passwd, dbname);
}

OcciDemo::~OcciDemo() {
        cout << "delete OcciDemo" << endl;
        env->terminateConnection(conn);
        Environment::terminateEnvironment(env);
}

void OcciDemo::displayTable() {
        Statement *stmt = conn->createStatement();
        ResultSet *rs = stmt->executeQuery("select id from usr");
        try {
                while (rs->next()) {
                        cout << rs->getInt(1) << endl;
                }
        } catch (SQLException se) {
                cout << "Error number: " << se.getErrorCode() << endl;
                cout << se.getMessage() << endl;
        }
}



/*
 * t_occi.cpp
 *
 *  Created on: Apr 22, 2009
 *      Author: hanchen
 */
#include "occi.h"

int main(void) {
        OcciDemo *occi = new OcciDemo("hanchen", "123456", "orcl");
        occi->displayTable();
        delete (occi);
        return 0;
}

二、网上关于C++导出成为C的so文件例子很多,照葫芦画瓢即可自然,实际上并不需要使用occi.cpp来操作,直接在C源文件里操作OCCI导出即可。
/*
 * e_occi.h
 *
 *  Created on: Apr 22, 2009
 *      Author: hanchen
 */

#ifndef E_OCCI_H_
#define E_OCCI_H_

#ifdef _cplusplus
extern "C"
{
#endif
void eocci_test();
#ifdef _cplusplus
}
#endif
#endif /* E_OCCI_H_ */


/*
 * e_occi.cpp
 *
 *  Created on: Apr 22, 2009
 *      Author: hanchen
 */
#ifndef _cplusplus
#define _cplusplus
#endif

#include "occi.h"
#include "e_occi.h"

void eocci_test() {
        OcciDemo occi("hanchen", "123456", "orcl");
        occi.displayTable();
}


/*
 * t_e_occi_so.c
 *
 *  Created on: Apr 22, 2009
 *      Author: hanchen
 */

#include <stdio.h>
#include <dlfcn.h>
#include "e_occi.h"

int main(void) {
        void (*df)();
        void *hl;

        hl = dlopen("./e_occi.so", RTLD_LAZY);
        df = dlsym(hl, "eocci_test");
        (*df)();
        dlclose(hl);

        return 0;
}

三、动态链接虽然简单,但操作麻烦,如果程序员自己能控制代码的话,做静态链接则是一种更好的选择
/*
 * t_e_occi_a.c
 *
 *  Created on: Apr 22, 2009
 *      Author: hanchen
 */

#include <stdio.h>
#include <dlfcn.h>
#include "e_occi.h"

int main(void) {
        eocci_test();

        return 0;
}


四、makefile,想必您看到这里已经很厌烦了,光看代码不一定能实际运用,最后是三个单元的makefile集合,什么,你说你不知道makefile是什么东西?。。。如果你是windows用户,并且在windows下开发C程序的话,那么您没必要看下去了,如果你是linux C程序员,那我建议你还是先学习下linux C开发的基础。。。废话少说。。。看文件
ORACLE_HOME=/opt/oracle/ora11

TARGET=t_occi t_e_occi_so t_e_occi_a

all:$(TARGET)

occi.o:occi.cpp
        g++ -o $@ $^ -c -I$(ORACLE_HOME)/rdbms/public
        
t_occi.o:t_occi.cpp
        g++ -o $@ $^ -c -I$(ORACLE_HOME)/rdbms/public
        
e_occi.o:e_occi.cpp
        g++ -o $@ $^ -c -I$(ORACLE_HOME)/rdbms/public
        
e_occi.so:e_occi.o occi.o
        g++ -o $@ $^ -shared
        
t_e_occi_a.o:t_e_occi_a.c
        gcc -o $@ $^ -c

t_occi:t_occi.o occi.o
        g++ -o $@ $^ -L$(ORACLE_HOME)/lib -locci -lclntsh
        
t_e_occi_so:e_occi.so
        gcc -o $@ t_e_occi_so.c -ldl -L$(ORACLE_HOME)/lib -locci -lclntsh
        
t_e_occi_a:t_e_occi_a.o e_occi.o occi.o
        gcc -o $@ $^ -L$(ORACLE_HOME)/lib -locci -lclntsh
        
clean:
        rm -rf *.o *.so
        rm -rf $(TARGET)

    makefile写的很复杂,一会是gcc,一会儿是g++,您耐心慢慢读,如果你无法编译出C++版本通过OCCI操作数据的程序,那么建议您读读另外一篇文章 linux下使用occi链接oracle11



没有评论: