OCI编程高级篇(一) 数组插入
访问www.tomcoding.com网站,学习Oracle内部数据结构,详细文档说明,下载Oracle的exp/imp,DUL,logminer,ASM工具的源代码,学习高技术含量的内容。
在前面我们介绍了向数据库表中插入数据的方法,在例子中一次插入一条数据,对于处理大量数据的场景这种方式显然效率低下。幸运的是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条。

浙公网安备 33010602011771号