Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3902584
  • 博文数量: 534
  • 博客积分: 10470
  • 博客等级: 上将
  • 技术积分: 4800
  • 用 户 组: 普通用户
  • 注册时间: 2006-05-26 14:08
文章分类

全部博文(534)

文章存档

2021年(1)

2019年(1)

2017年(1)

2016年(2)

2013年(2)

2012年(10)

2011年(43)

2010年(10)

2009年(17)

2008年(121)

2007年(253)

2006年(73)

分类:

2006-11-07 16:48:22

OCI程序结构:
   1>. 初始化OCI程序环境和线程.
   2>. 分配需要的句柄和建立服务联结, 用户会话.
   3>. 按自己的需要来书写SQL语句, 准备与服务器交换数据.
   4>. 执行SQL语句, 准备一个新的会话或回到步骤3.
   5>. 终止用户会话和服务联接.
   6>. 释放句柄.

句柄:
   句柄就是指向一块由OCI函数分配的存储区, 他同我们长说的指针没什么区别. 你可以使用句柄来访问存储的内容或联结信息. 当然你不可以直接访问的, 因为你不知道你所指的这块存储的结构信息(也就是数据怎么存放的, 关键是数据的存放次序以及这些数据的含义是什么.)
   要访问存储区的信息就必需用OCI函数库了, 使用OCI函数库可以让我们没有必要关心句柄下面的内容是什么, 你只需要知道他是一个指针, 但具体指向什么地方就不是开发人员关心的了. 不知道我说了这么一堆有没有说清楚(不懂就: ganhk(at)dsgdata.com).

OCIAttrGet() and OCIAttrSet()
这是大部分OCI句柄修改自己属性的函数.

OCI句柄的类型有:
----------------------------------------------------------------------
描叙             C中的数据类型         句柄类型
----------------------------------------------------------------------
OCI环境句柄         OCIEnv             OCI_HTYPE_ENV
OCI错误            OCIError         OCI_HTYPE_ERROR
OCI服务内容句柄     OCISvcCtx         OCI_HTYPE_SVCCTX
OCI语句句柄         OCIStmt             OCI_HTYPE_STMT
OCI邦定句柄         OCIBind             OCI_HTYPE_BIND
OCI定义句柄         OCIDefine         OCI_HTYPE_DEFINE
OCI描叙句柄         OCIDescribe         OCI_HTYPE_DESCRIBE
OCI服务句柄         OCIServer         OCI_HTYPE_SERVER
OCI用户会话句柄     OCISession         OCI_HTYPE_SESSION
OCI授权信息句柄        OCIAuthInfo         OCI_HTYPE_AUTHINFO
OCI联接池句柄         OCICPool         OCI_HTYPE_CPOOL
OCI会话池句柄         OCISPool         OCI_HTYPE_SPOOL
OCI事物句柄         OCITrans         OCI_HTYPE_TRANS
OCI复杂对象句柄        OCIComplexObject     OCI_HTYPE_COMPLEXOBJECT
OCI线程句柄         OCIThreadHandle         N/A
OCI订阅句柄         OCISubscription         OCI_HTYPE_SUBSCRIPTION
OCI直接路径内容句柄     OCIDirPathCtx         OCI_HTYPE_DIRPATH_CTX
OCI直接路径功能内容句柄    OCIDirPathFuncCtx     OCI_HTYPE_DIRPATH_FN_CTX
OCI直接路径列数组句柄     OCIDirPathColArray     OCI_HTYPE_DIRPATH_COLUMN_ARRAY
OCI直接路径流句柄     OCIDirPathStream         OCI_HTYPE_DIRPATH_STREAM
OCI进程句柄         OCIProcess         OCI_HTYPE_PROCESS
-----------------------------------------------------------------------------

句柄的层次性:
环境句柄(OCIEnv)    |--- 用户会话句柄    (OCISession)    
        |--- 直接路径内容句柄    (OCIDirPathCtx)
        |--- 线程句柄        (OCIThreadHandle)
        |--- 复杂对象句柄    (OCIComplexObject)
        |--- 订阅句柄        (OCISubscription)
        |--- 描叙句柄        (OCIDescribe)
        |--- 语句句柄        (OCIStmt)
        |--- 服务内容句柄    (OCISvcCtx)
        |--- 错误句柄        (OCIError)
        |--- 服务器句柄        (OCIServer)
        |--- 联结池句柄        (OCICPool)

    所有用户分配句柄和初始化函数OCIHandleAlloc(), 有点像malloc(). 线程句柄分配空间和初始化函数OCIThreadHndInit(). 所有句柄的空间释放函数OCIHandleFree(), 有点象free().

环境句柄(OCIEnv):
    OCIEnv的创建函数OCIEnvCreate() 或 OCIEnvNlsCreate().
    环境句柄是所有句柄的基础, 他指向一块内存区, 其他的句柄在该句柄的基础上进行别的句柄空间的分配和操作. 当在多线程的程序中如果只有一个环境句柄时, 注意多线程操作同一个环境时的锁问题!

错误句柄(OCIError)
    错误句柄几乎在所有的程序中都要使用, 他指向一块存放错误信息的地方, 当执行完一个OCI函数后如果出错就可以通过OCIErrorGet()来提起错误信息.

#################################
OCI中的数据类型($ORACLE_HOME/rdbms/demo/oratypes.h)
--------------------------------
typedef unsigned char     ub1;
typedef signed char     sb1;
typedef char         eb1;

typedef sb1         b1;
---------------------------------
typedef unsigned short     ub2;
typedef signed short     sb2;
typedef short         eb2;

typedef sb2        b2;
---------------------------------
typedef unsigned int    ub4;
typedef signed int    sb4;
typedef int        eb4;

typedef sb4        b4;
typedef eb4        deword;
typedef ub4        duword;
typedef sb4        dsword;
typedef dsword        dword;
typedef ub4        dsize_t;
---------------------------------
typedef unsigned long    ub8;
typedef signed long    sb8;

---------------------------------
typedef    unsigned char    text;
typedef unsigned char    OraText;
typedef unsigned short    utext;
typedef int        boolean;

---------------------------------
typedef int        eword;
typedef unsigned int    uword;
typedef signed int     sword;

---------------------------------
typedef unsigned long    ubig_ora;
typedef signed long    sbig_ora;

---------------------------------
#define    CONST        const
#define    dvoid        void

############################################
eg1:
该示例是仿照$ORACLE_HOME/rdbms/demo/cdemocp.c文件修改的.

测试环境:
OS:    RedHat 9.0
Kernel:    2.4.20-8
Oracle:    9.2.0.4.0

------------
Makefile
------------
OBJS=cdemocp.o
                                                                                                               
OBJ_EXE=cdemocp
                                                                                                              
all: ${OBJ_EXE}
                                                                                                              
${OBJ_EXE}: ${OBJS}
        /usr/bin/gcc -L${ORACLE_HOME}/lib/ -L${ORACLE_HOME}/rdbms/lib -o $@ $< -lclntsh -ldl -lm
                                                                                                              
.SUFFIXES: .cc .c .o
.c.o:
        /usr/bin/gcc -I. -I/usr/include         \
        -I${ORACLE_HOME}/rdbms/demo -I${ORACLE_HOME}/rdbms/public       \
        -I${ORACLE_HOME}/rdbms/plsql/public -I${ORACLE_HOME}/network/public     \
        -I${ORACLE_HOME}/precomp/public -c $<
                                                                                                              
clean:
        rm -f *.o
        rm -f ${OBJ_EXE}

------------
cdemocp.c
------------
#include
#include
#include
#include

static void check_error(OCIError *errhp, sword status)
{
  text    errbuf[512];
  sb4    errcode;

  switch (status)
  {
    case OCI_SUCCESS:
      break;

    case OCI_SUCCESS_WITH_INFO:
      fprintf(stderr, "Error - OCI_SUCCESS_WITH_INFO\n");
      break;

    case OCI_NEED_DATA:
      fprintf(stderr, "Error - OCI_NEED_DATA\n");
      break;

    case OCI_NO_DATA:
      fprintf(stderr, "Error - OCI_NO_DATA\n");
      break;

    case OCI_ERROR:
      errcode = 0;
      OCIErrorGet((dword *)errhp, (ub4)1, (text *)NULL, &errcode,
        errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR);
      fprintf(stderr, "Error - %s\n", errbuf);
      break;

    case OCI_INVALID_HANDLE:
      fprintf(stderr, "Error - OCI_INVALID_HANDLE\n");
      break;

    case OCI_STILL_EXECUTING:
      fprintf(stderr, "Error - OCI_STILL_EXECUTING\n");
      break;

    case OCI_CONTINUE:
      fprintf(stderr, "Error - OCI_CONTINUE\n");
      break;

    default:
      fprintf(stderr, "Error - Unknown Error Code\n");
      break;
  }
}

/* EXECUTE SELECT */
static void query_rows(OCIEnv *envhp, OCIError *errhp,
    const OraText *username, const OraText *password, const OraText *database)
{
  int        i;
  sword        lstat, status;
  text        sqlstr[256];

  float        emp_sal;
  ub4        emp_no, emp_dept;
  text        emp_name[10], emp_job[9];

  OCIStmt    *stmthp    = (OCIStmt *)0;
  OCISvcCtx    *svchp     = (OCISvcCtx *)0;
  OCIDefine    *defhp1    = (OCIDefine *)0,
                *defhp2    = (OCIDefine *)0,
                *defhp3    = (OCIDefine *)0,
                *defhp4    = (OCIDefine *)0,
                *defhp5    = (OCIDefine *)0;

  /* Login Oracle */
  lstat = OCILogon(envhp, errhp, &svchp,
        (CONST OraText *)username, (ub4)strlen((const char *)username),
        (CONST OraText *)password, (ub4)strlen((const char *)password),
        (CONST OraText *)database, (ub4)strlen((const char *)database));
  if (lstat)
  {
    check_error(errhp, lstat);
    return;
  }

  sprintf(sqlstr, "SELECT empno, ename, job, sal, deptno FROM emp ORDER BY empno");
 
  OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT,
    (size_t)0, (dvoid **)0);

  check_error(errhp, OCIStmtPrepare(stmthp, errhp,
    (text *)sqlstr, (ub4)strlen((const char *)sqlstr), OCI_NTV_SYNTAX, OCI_DEFAULT));

  check_error(errhp, OCIDefineByPos(stmthp, &defhp1, errhp, (ub4)1,
    (dvoid *)&emp_no, (sb4)sizeof(emp_no), (ub2)SQLT_INT,
    (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT));
  check_error(errhp, OCIDefineByPos(stmthp, &defhp2, errhp, (ub4)2,
    (dvoid *)&emp_name, (sb4)sizeof(emp_name), (ub2)SQLT_STR,
    (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT));
  check_error(errhp, OCIDefineByPos(stmthp, &defhp3, errhp, (ub4)3,
    (dvoid *)&emp_job, (sb4)sizeof(emp_job), (ub2)SQLT_STR,
    (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT));
  check_error(errhp, OCIDefineByPos(stmthp, &defhp4, errhp, (ub4)4,
    (dvoid *)&emp_sal, (sb4)sizeof(emp_sal), (ub2)SQLT_FLT,
    (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT));
  check_error(errhp, OCIDefineByPos(stmthp, &defhp5, errhp, (ub4)5,
    (dvoid *)&emp_dept, (sb4)sizeof(emp_dept), (ub2)SQLT_INT,
    (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT));

  if (lstat = OCIStmtExecute(svchp, stmthp, errhp, (ub4)0,
    (ub4)0, (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT))
  {
    check_error(errhp, lstat);
    return;
  }

  status = 0;
  status = OCIStmtFetch(stmthp, errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
  while (status != OCI_NO_DATA)
  {
    printf("emp_no: %u \t emp_name: %s \t job: %s \tsalary: %7.2f    \tdept_no: %u\n",
    emp_no, emp_name, emp_job, emp_sal, emp_dept);
    status = OCIStmtFetch(stmthp, errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
  }

  check_error(errhp, OCIHandleFree((dvoid *)stmthp, OCI_HTYPE_STMT));
  check_error(errhp, OCILogoff((dvoid *)svchp, errhp));
}

static void insert_rows(OCIEnv *envhp, OCIError *errhp,
    const OraText *username, const OraText *password,
    const OraText *database, text *sqlstr)
{
  sword        lstat;
  OCISvcCtx    *svchp     = (OCISvcCtx *)0;
  OCIStmt    *stmthp    = (OCIStmt *)0;

  if (lstat = OCILogon(envhp, errhp, &svchp,
    (CONST OraText *)username, (ub4)strlen((const char *)username),
    (CONST OraText *)password, (ub4)strlen((const char *)password),
    (CONST OraText *)database, (ub4)strlen((const char *)database)))
  {
    check_error(errhp, lstat);
    return;
  }

  OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT,
    (size_t)0, (dvoid **)0);

  check_error(errhp, OCIStmtPrepare(stmthp, errhp,
    (CONST OraText *)sqlstr, (ub4)strlen((const char *)sqlstr),
    OCI_NTV_SYNTAX, OCI_DEFAULT));
  check_error(errhp, OCIStmtExecute(svchp, stmthp, errhp,
    (ub4)1, (ub4)0, (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT));
  check_error(errhp, OCITransCommit(svchp, errhp, (ub4)0));

  check_error(errhp, OCIHandleFree((dvoid *)stmthp, OCI_HTYPE_STMT));
  check_error(errhp, OCILogoff((dvoid *)svchp, errhp));
}

int main(int argc, char **argv)
{
  CONST OraText    *database     = (OraText *)"";
  CONST OraText    *username    = (OraText *)"scott";
  CONST OraText *password    = (OraText *)"tiger";

  OCIEnv    *envhp;
  OCIError    *errhp;
  text        sqlstr[256];
  ub4        conMax, conIncr, conMin;

  OCIEnvCreate(&envhp, OCI_THREADED, (dvoid *)0, NULL, NULL, NULL, 0, (dvoid **)0);

  OCIHandleAlloc((dvoid *)envhp, (dvoid *)&errhp, OCI_HTYPE_ERROR,
    (size_t)0, (dvoid **)0);

  conMax = 3;
  conMin = 1;
  conIncr= 1;

  sprintf(sqlstr, "INSERT INTO emp(empno, ename, job, sal, deptno) VALUES(30, 'Gan', 'DBA', 9000, 10)");
  printf("\nInsert values to the table: \n%s\n", sqlstr);
  insert_rows(envhp, errhp, username, password, database, sqlstr);

  printf("\nDisplay the table information.\n");
  query_rows(envhp, errhp, username, password, database);

  check_error(errhp, OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR));
  return (0);
}

##################################
说明:
IN 该参数提供输入功能; OUT 该参数将会返回值或该参数所指的内容将会被修改.

功能: 为用户创建一个简单的会话联接.
sword OCILogon (    OCIEnv        *envhp,        /* IN         环境句柄 */
        OCIError        *errhp,        /* IN/OUT     错误句柄 */
        OCISvcCtx    **svchp,        /* IN/OUT    服务内容句柄 */
        CONST OraText    *username,    /* IN        Oracle用户名 */
        ub4        uname_len,    /* IN        用户名长度 */
        CONST OraText    *password,    /* IN        该用户密码 */
        ub4        passwd_len,     /* IN        密码长度 */
        CONST OraText     *dbname,        /* IN        数据库SID, 本地可以用"", 远程数据库见tnsnames.ora文件 */
        ub4        dbname_len    /* IN        SID的长度 */
        );
创建会话的目的关键是返回了一个svchp句柄, 在接下来的操作中将会很有用. 当然OCILogoff()的操作就与Logon()的操作相反了.
---------------------------

功能: 关闭会话
sword OCILogoff (    OCISvcCtx    *svchp,        /* IN        服务内容句柄 */
        OCIError        *errhp        /* IN/OUT */
        );
---------------------------

功能: 创建一个会话, 该会话可能是已经建立了的联接池中的一个虚联接.
sword OCILogon2(    OCIEnv        *envhp,
        OCIError        *errhp,
        OCISvcCtx    **svchp,
        CONST OraText    *username,
        ub4        uname_len,
        CONST OraText    *password,
        ub4        passwd_len,
        CONST OraText    *dbname,        /* IN    对与联接池来说该处应该为联接池名 */
        ub4        dbname_len,    /* IN    对与联接池来说该处应该为联接池名长度 */
        ub4        mode        /* IN   见下面 */
        );
mode可以为:
OCI_DEFAULT            设置为这个与用OCILogon()函数功能一样
OCI_LOGON2_STMTCACHE    允许SQL语句缓存

对于联接池合法值有:
OCI_LOGON2_CPOOL
OCI_CPOOL

如:$ORACLE_HOME/rdbms/demo/cdemocp.c中的语句:
/* Create the connection pool for multi-thread */
lstat = OCIConnectionPoolCreate (envhp, errhp, poolhp,
        &poolName, &poolNameLen, database, (sub4)strlen((const char *)database),
        conMin, conMax, conIncr,
        appusername, (sb4)strlen((const char *)appusername), apppassword, (sb4)strlen((const char *)apppassword),
        OCI_DEFAULT);

/* Logon in Connection Pool mode */
if (lstat = OCILogon2 (envhp, errhp, &svchp,
              (CONST OraText *)username, (ub4)strlen((const signed char *)username),
              (CONST OraText *)password, (ub4)strlen((const signed char *)password),
              (CONST OraText *)poolName, (ub4)poolNameLen, OCI_CPOOL))

------------------------------------------
创建一个联接池.
sword OCIConnectionPoolCreate (   
        OCIEnv        *envhp,
        OCIError        *errhp,
        OCICPool    *poolhp,        /* IN     已经分配了空间的联接池句柄 */
        OraText        **poolName,    /* OUT    联接池名 */
        sb4        **poolNameLen,    /* OUT 联接池名的长度 */
        CONST OraText    *dblink,        /* IN    数据库联接SID */
        sb4        dblinkLen,    /* IN    联接字符的长度 */
        ub4        connMin,        /* IN    联接池中最小联接数 */
        ub4        connMax,        /* IN    联接池中最大联接数 */
        ub4        connIncr,        /* IN    联接池中联接数每次增加数 */
        CONST OraText    *poolUsername,    /* IN    创建联接池用户名 */
        ub4        poolUserLen,    /* IN    用户名长度 */
        CONST OraText    *poolPassword,    /* IN     密码 */
        ub4        poolPassLen,    /* IN    密码长度 */
        ub4        mode        /* IN    见下面 */
            );
mode可以为:
OCI_DEFAULT         通常就使用该参数
OCI_CPOOL_REINITIALIZE    可以动态的改变联接池属性(如: connMin, connMax, connIncr)

与创建联接池相反的函数:OCIConnectionPoolDestroy();
sword OCIConnectionPoolDestroy (
        OCICPool    *poolhp,
        OCIError        *errhp,
        ub4        mode        /* 目前该函数只支持OCI_DEFAULT功能 */
            );

---------------------------------------
阅读(4067) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~