OCI编程基础篇(七) 插入数据

访问www.tomcoding.com网站,学习Oracle内部数据结构,详细文档说明,下载Oracle的exp/imp,DUL,logminer,ASM工具的源代码,学习高技术含量的内容。

这一节我们来看看怎样向数据库表中插入一条数据,插入数据也有下面几个步骤。

1. 分配一个SQL语句句柄,OCIHandleAlloc()

2. 准备SQL语句,OCIStmtPrepare()

3. SQL语句绑定要插入的数据,OCIBindByPos()

4. 执行SQL语句,OCIStmtExecute()

5. 提交数据库改变,OCITransCommit()

下面我们看一下新出现的OCI函数的原型和参数。

第一个函数是准备SQL语句,原型如下。

sword OCIStmtPrepare ( OCIStmt *stmtp,
    OCIError         *errhp,
    const OraText *stmt,
    ub4                  stmt_len,
    ub4                  language,
    ub4                  mode );

stmtp是一个输入参数,是第一步中OCIHandleAlloc()分配的SQL语句句柄。

errhp是一个输入参数,用于调用出错时返回错误码和错误信息文本。

stmt是一个输入参数,是要执行的SQL语句的文本,必须是一个NULL结束的字符串。

stmt_len是一个输入参数,是SQL语句文本的长度,一定不能赋值为0

language是一个输入参数,取值OCI_NTV_SYNTAX,本地分析SQL语法。

mode是一个输入参数,唯一取值为OCI_DEFAULT

这里重点说一下SQL语句文本,这个文本是有特殊格式的,如果插入一个表的数据有三个字段,假设表名叫做tab1,那么文本格式为INSERT INTO tab1 VALUES (:1, :2, :3)。这里的1,2,3叫做占位符,后续要通过绑定函数把插入的值与占位符关联起来。占位符也可以叫别的名字,只要前面是冒号开头的都是占位符,用1,2,3来表示是为了与占位符的位置一致。

第二个函数是绑定数据,原型如下。

sword OCIBindByPos ( OCIStmt *stmtp,
    OCIBind   **bindpp,
    OCIError  *errhp,
    ub4          position,
    void         *valuep,
    sb4          value_sz,
    ub2         dty,
    void        *indp,
    ub2         *alenp,
    ub2         *rcodep,
    ub4         maxarr_len,
    ub4         *curelep,
    ub4         mode );

stmtp是一个输入参数/输出参数,是要处理的SQL语句句柄。

bindpp是一个输入/输出参数,这时一个绑定句柄的指针,调用函数后,会隐式的分配一个句柄,这个参数把绑定句柄带回,后续所有针对这个绑定值的操作都通过这个句柄进行。绑定句柄在语句句柄释放时也会隐式的释放掉。如果不需要对绑定值进行其他操作,可以赋值为NULL

errhp是一个输入/输出参数,用于函数调用出错后获取错误码和错误信息文本。

position是一个输入参数,指定占位符的位置,从1开始计算位置。

valuep是一个输入/输出参数,如果是一个宿主变量,输入的就是这个变量的地址,如果是一个宿主变量数组,输入的就是数组的地址。在一些PL/SQL块中如果需要返回值,也是要用到绑定函数的,所以这个值也可以用作输出参数。

value_sz是一个输入参数,是绑定数据的最大可能长度,比如你定义了一个100字符的数组,那么这个参数就赋值为100,不管实际的数据长度是多少。

dty是一个输入参数,指定数据类型。典型的整数为SQLT_INT,字符串为SQLT_STR

indp是一个输入/输出参数,指向一个指示变量或指示变量数组,指示变量是一个sb2类型的16位整数,如果绑定值是NULL,指示变量要设置为-1,否则设置为0。如果绑定的是一个输出变量,指示变量也要设置为0

alenp是一个输入/输出参数,绑定数据的实际大小。指向一个ub2类型的整数或整数数组。

rcodep是一个输出参数,返回字段级的错误码。指向一个ub2类型的整数或整数数组。

maxarr_len是一个输入参数,最大数组元素个数,只用于PL/SQL中的索引表绑定。

curelep是一个输入/输出参数,实际数组元素个数,只用于PL/SQL中的索引表绑定。

mode是一个输入参数,指示绑定模式。一般取值为OCI_DEFAULT

函数中的数据类型还有很多种,这里列一个表看看其他取值。

SQLT_CHR

对应VARCHAR2,在C语言中对应一个字符数组char[n]

SQLT_NUM

对应Oracle格式的NUMBER类型

SQLT_INT

对应64位及以下的有符号整数

SQLT_UIN

对应64位及以下的无符合整数

SQLT_STR

对应一个NULL结尾的字符串

SQLT_LNG

对应LONG类型

SQLT_DAT

对应Oracle格式的日期类型

SQLT_BFLOAT

对应BINARY_FLOAT类型

SQLT_BDOUBLE

对应BINARY_DOUBLE类型

SQLT_BIN

对应RAW类型

SQLT_LBI

对应LONG RAW类型

SQLT_AFC

对应CHAR类型

第三个函数是执行语句,原型如下。

sword OCIStmtExecute ( OCISvcCtx *svchp,
    OCIStmt                 *stmtp,
    OCIError                 *errhp,
    ub4                          iters,
    ub4                          rowoff,
    const OCISnapshot *snap_in,
    OCISnapshot           *snap_out,
    ub4                          mode );

svchp是一个输入/输出参数,是连接数据库时分配的服务上下文句柄。

stmtp是一个输入/输出参数,SQL语句句柄。

errhp是一个输入/输出参数,用于获取错误码和错误信息文本。

iters是一个输入参数,对于更新数据库的操作和查询数据库的操作,含义是不一样的。对于更新数据库操作,这是迭代次数,SQL语句要执行iters-rowoff次。对于查询操作一般设置这个参数为0,如果不为0,表示执行语句后,预先获取的数据条数。

rowoff是一个输入参数,对于数组操作,指示从哪条数据开始处理。第一条从0开始计算。

snap_in是一个输入参数,对于查询操作,输入一个快照句柄,为了几个不同的查询用同一个快照取得相同时间点的数据。对更新数据库操作,这个参数会被忽略。一般赋值为NULL即可。

snap_out是一个输出参数,对于查询操作,输出一个当前SCN时间点的快照。对更新数据库操作,这个参数会被忽略。一般赋值为NULL即可。

mode是一个输入参数,一般取值为OCI_DEFAULT

第四个函数是提交改变,原型如下。

sword OCITransCommit ( OCISvcCtx *svchp,
    OCIError *errhp,
    ub4          flags );

svchp是一个输入参数,服务上下文句柄。

errhp是一个输入参数,错误句柄,获取出错的错误码和错误信息文本。

flags是一个输入参数,一般取值为OCI_DEFAULT

举一个例子,创建一个表,然后向表中插入一条数据,在sqlplus中操作如下。

CREATE TABLE test_tab (ID NUMBER, NAME CHAR(30), ADDR VARCHAR2(200));
INSERT INTO test_tab VALUES (1, 'aaaaaaaa', 'bbbbbbbbbbbbbbbbbbbb');
COMMIT;
下面我们用OCI程序插入,源代码如下。

 

OCIEnv		*envhp = NULL;
OCIError	*errhp = NULL;
OCIServer	*svrhp = NULL;
OCISession	*usrhp = NULL;
OCISvcCtx	*svchp = NULL;
OCIStmt		*smthp = NULL;

/* 插入一条数据 */
int insert_one_row(void){
    sword	rc;
    int		slen;
    sb2		ind_id;
    sb2		ind_name;
    sb2		ind_addr;
    ub2		alen_id;
    ub2		alen_name;
    ub2		alen_addr;
    ub2		rcode_id;
    ub2		rcode_name;
    ub2		rcode_addr;
    int32_t	id;
    char	name[32];
    char	addr[256];
    OCIBind	*bndp;
    char	sqltxt[1024];

    /* 分配OCI语句句柄 */
    rc = OCIHandleAlloc(
        (void *)envhp,
        (void **)&smthp,
        OCI_HTYPE_STMT,
        0,
        (void **)NULL
    );

    if (rc != OCI_SUCCESS) {
        fprintf(stderr, "OCIHandleAlloc() - allocate statement handle error !\n");
        return (-1);
    }

    /* 生成SQL语句文本 */
    strcpy(sqltxt, "INSERT INTO test_tab (ID, NAME, ADDR) VALUES (:1, :2, :3)");
    slen = strlen(sqltxt);

    /* 准备语句 */
    if (check_oci_error(errhp,
        OCIStmtPrepare(smthp, errhp, (const OraText *)sqltxt, slen,
            OCI_NTV_SYNTAX, OCI_DEFAULT)) < 0)
        return (-1);

    /* 绑定第一个占位符ID */
    if (check_oci_error(errhp,
        OCIBindByPos((OCIStmt *)smthp,
            (OCIBind **)&bndp,
            errhp,
            (ub4)1,	            /* position */
            (void *)&id,        /* valuep */
            (sb4)4,             /* value_sz */
            (ub2)SQLT_INT,      /* dty */
            (void *)&ind_id,    /* indp */
            (ub2 *)&alen_id,    /* alenp */
            (ub2 *)&rcode_id,   /* column return code pointer */
            (ub4)0,             /* maxarr_len */
            (ub4 *)NULL,        /* curelep */
            (ub4)OCI_DEFAULT)   /* mode */
        ) < 0)
        return (-1);

    /* 绑定第二个占位符NAME */
    if (check_oci_error(errhp,
        OCIBindByPos((OCIStmt *)smthp,
            (OCIBind **)&bndp,
            errhp,
            (ub4)2,             /* position */
            (void *)name,       /* valuep */
            (sb4)30,            /* value_sz */
            (ub2)SQLT_STR,      /* dty */
            (void *)&ind_name,  /* indp */
            (ub2 *)&alen_name,  /* alenp */
            (ub2 *)&rcode_name, /* column return code pointer */
            (ub4)0,             /* maxarr_len */
            (ub4 *)NULL,        /* curelep */
            (ub4)OCI_DEFAULT)   /* mode */
        ) < 0)
        return (-1);

    /* 绑定第三个占位符ADDR */
    if (check_oci_error(errhp,
        OCIBindByPos((OCIStmt *)smthp,
            (OCIBind **)&bndp,
            errhp,
            (ub4)3,             /* position */
            (void *)addr,       /* valuep */
            (sb4)200,           /* value_sz */
            (ub2)SQLT_STR,      /* dty */
            (void *)&ind_addr,  /* indp */
            (ub2 *)&alen_addr,  /* alenp */
            (ub2 *)&rcode_addr, /* column return code pointer */
            (ub4)0,             /* maxarr_len */
            (ub4 *)NULL,        /* curelep */
            (ub4)OCI_DEFAULT)   /* mode */
        ) < 0)
        return (-1);

    /* 赋值绑定的变量数据 */
    id = 1;
    strcpy(name, "aaaaaaaa");
    strcpy(addr, "bbbbbbbbbbbbbbbbbbbb");
    /* 指示符赋值为0,插入非NULL数据 */
    ind_id    = 0;
    ind_name  = 0;
    ind_addr  = 0;
    /* 赋值变量的真实数据长度 */
    alen_id   = 4;
    alen_name = strlen(name) + 1;
    alen_addr = strlen(addr) + 1;

    /* 执行OCI语句 */
    if (check_oci_error(errhp,
        OCIStmtExecute(svchp,
            smthp,              /* stmthp */
            errhp,              /* errhp */
            1,                  /* iters */
            0,                  /* rowoff */
            NULL,               /* snap_in */
            NULL,               /* snap_out */
            OCI_DEFAULT)        /* mode */
        ) < 0)
        return (-1);

    /* 提交改变的数据 */
    if (check_oci_error(errhp,
        OCITransCommit(svchp, errhp, OCI_DEFAULT)) < 0)
        return (-1);

    return (0);
}

 

上面的程序中我们使用了前面编写的错误处理函数check_oci_error(),简化代码,便利阅读。如果在上面的例子中插入第二条数据,不需要重新绑定,只需要在执行语句前把变量的值改变,然后执行语句就能插入数据。

 

posted @ 2025-08-14 14:46  汤姆花花  阅读(18)  评论(0)    收藏  举报