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(),简化代码,便利阅读。如果在上面的例子中插入第二条数据,不需要重新绑定,只需要在执行语句前把变量的值改变,然后执行语句就能插入数据。

浙公网安备 33010602011771号