OCI编程高级篇(一) 数组插入

在前面我们介绍了向数据库表中插入数据的方法,在例子中一次插入一条数据,对于处理大量数据的场景这种方式显然效率低下。幸运的是OCI提供了让我们批量插入大量数据的方法,这就是数组插入。

数组插入的步骤与单条插入时基本一样,只是在绑定占位符时,输入的是一个数组地址,而不是一个单独的变量地址,indp,alenp,rcodep也都指向一个数组。调用完OCIBindByPos()函数后,还要调用一个OCIBindArrayOfStruct()函数,这个函数定义每个变量跳过的字节个数,以便从开始能找到后续变量的地址。函数原型和参数如下。

sword OCIBindArrayOfStruct ( OCIBind *bindp,
    OCIError *errhp,
    ub4 pvskip,
    ub4 indskip,
    ub4 alskip,
    ub4 rcskip );

bindp是一个输入/输出参数,是一个绑定句柄,由前一个函数OCIBindByPos()隐式分配得来。

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

pvskip是一个输入参数,是绑定的数据数组值要跳过的字节数。

indskip是一个输入参数,是指示变量要跳过的字节数。

alskip是一个输入参数,是实际的数据长度跳过的字节数。

rcskip是一个输入参数,是字段级出错返回码跳过的字节数。

下面来看看这个函数的用法,还是举一个例子来说明,先看一下我们前面创建的test_tab表,表结构如下。CREATE TABLE test_tab (ID NUMBER, NAME CHAR(30), ADD VARCHAR2(200))。假如我们只向表中插入ID字段的数据,插入10条记录,我们先定义一个整数数组int id[10],用于存放插入的数据,然后定义三个数组sb2 ind_id[10],ub2 alen_id[10],ub2 rcode_id[10]分别用于指示变量,实际长度和返回码。我们先来看一下OCIBindArrayOfStruct()函数中跳过参数的取值,先看插入的数值,id[0]的地址与数组首地址id是一样的,id[1]的地址是id+sizeof(int),id[2]的地址是id+2*sizeof(int),可以看到每个元素相对于前一个元素跳过的字节数是sizeof(int),就是pvskip的值。再看指示变量,ind_id[0]的地址与数组首地址ind_id一样,ind_id[1]的地址是ind_id+sizeof(sb2),当前元素相对与前一个元素跳过的字节数是sizeof(sb2),就是indskip的值。同样我们可以判断alskip和rcskip的值。

下面我们看一个完整的例子,用数组在test_tab表中插入10条数据。

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


/* 数组插入10条数据 */
int insert_array(void)
{
    int     i;
    sword	rc;
    int		slen;
    sb2		ind_id[10];
    sb2		ind_name[10];
    sb2		ind_addr[10];
    ub2		alen_id[10];
    ub2		alen_name[10];
    ub2		alen_addr[10];
    ub2		rcode_id[10];
    ub2		rcode_name[10];
    ub2		rcode_addr[10];
    int32_t	id[10];
    char	name[10][32];
    char	addr[10][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);

    /* 指定绑定参数跳过的字节数 */
    if (check_oci_error(errhp,
        OCIBindArrayOfStruct(bndp,
            sizeof(int32_t),
            sizeof(sb2),
            sizeof(ub2),
            sizeof(ub2))
        ) < 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);

    /* 指定绑定参数跳过的字节数,name定义的长度为32 */
    if (check_oci_error(errhp,
        OCIBindArrayOfStruct(bndp,
            32,
            sizeof(sb2),
            sizeof(ub2),
            sizeof(ub2))
        ) < 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);

    /* 指定绑定参数跳过的字节数,addr定义的长度为256 */
    if (check_oci_error(errhp,
        OCIBindArrayOfStruct(bndp,
            256,
            sizeof(sb2),
            sizeof(ub2),
            sizeof(ub2))
        ) < 0)
        return (-1);

    /* 赋值绑定的变量数据 */
    for (i=0; i<10; i++) {
        id[i] = i+10;
        memset(name[i], 'a', 10);
        memset(addr[i], 'b', 20);

        name[i][10] = '\0';
        addr[i][20] = '\0';

        /* 指示符赋值为0,插入非NULL数据 */
        ind_id[i]    = 0;
        ind_name[i]  = 0;
        ind_addr[i]  = 0;

        /* 赋值变量的真实数据长度 */
        alen_id[i]   = sizeof(int32_t);
        alen_name[i] = strlen(name[i]) + 1;
        alen_addr[i] = strlen(addr[i]) + 1;
    }

    /* 执行OCI语句,这里iters要赋值为10,表示插入数组中的10条记录 */
    if (check_oci_error(errhp,
        OCIStmtExecute(svchp,
            smthp,              /* stmthp */
            errhp,              /* errhp */
            10,                 /* 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);
}

要注意的是在OCIStmtExecute()函数中iters的值要输入10,才能插入数组中的10条数据,如果写成1,虽然数组中有10条记录,也只能插入1条。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值