OCI编程高级篇(十四) 直接路径装载设置字段信息
接着上一节的内容,直接路径装载我们从逻辑上应该知道要做哪些事情,在OCI插入数据的时候我们看到很简单,准备OCI语句,绑定数据,执行插入操作就可以了,但是在直接路径装载中却要设置这么多信息,其实在OCI插入数据时,这些信息是隐藏在了SQL语句中,比如INSERT INTO scott.test_tab (ID, NAME, ADDR) values (:1, :2, :3),这里面就包含了表名称,表的属主,字段的名称和字段的位置,这些信息在SQL语句语法分析时就会解析出来,然后在绑定操作中设置了数据类型,数据最大长度,数据值,数据实际长度。但是在直接路径装载时没有SQL语句,所以这些信息要一步一步来设置,先看看怎样设置字段名称,数据类型,最大长度等信息。
在设置字段信息之前,按照常理应该有一个跟字段关联的东西,在这里叫做字段描述符,一般情况下需要通过OCIDescriptorAlloc()函数来分配,但在直接路径操作中它是作为一个参数获得的,那么从哪里获得这个参数呢,在直接路径上下文句柄中有一个属性叫做字段列表,从这个字段列表中得到字段描述符。再来按正常顺序梳理一遍,从直接路径上下文句柄OCIDirPathCtx中得到属性字段列表(OCI_ATTR_LIST_COLUMNS),然后从字段列表中按照字段ID得到参数字段描述符,然后通过字段描述符设置各个字段的信息。
这里用到一个函数叫做OCIParamGet(),看一下它的原型和参数。
sword OCIParamGet ( const void *hndlp,
ub4 htype,
OCIError *errhp,
void **parmdpp,
ub4 pos );
hndlp是一个输入参数,是一个描述符句柄,函数从这个句柄得到参数。
htype是一个输入参数,是上面描述符句柄的类型,这里是OCI_DTYPE_PARAM,代表一个描述符句柄。
errhp是一个输入/输出参数,错误句柄,返回错误码和错误信息文本。
parmdpp是一个输出参数,返回一个特定位置的描述符句柄。
pos是一个输入参数,描述符句柄的位置,从1开始计算。
下面我们看看真实的设置字段信息的代码。
OCIEnv *envhp = NULL;
OCIError *errhp = NULL;
OCIServer *svrhp = NULL;
OCISession *usrhp = NULL;
OCISvcCtx *svchp = NULL;
struct dp_columns {
ub4 dtyp; /* 字段类型 */
ub4 clen; /* 字段最大长度 */
char name[32]; /* 字段名称 */
};
int dp_load(void)
{
int i;
ub4 buf_sz;
ub4 ncol;
OCIDirPathCtx *dpctx;
OCIDirPathColArray *dpca;
OCIDirPathStream *dpstr;
OCIParam *colLst = NULL;
OCIParam *colDsc = NULL;
struct dp_columms col[3];
/* 前面的代码略过去,下面是设置字段信息的代码部分 */
/* 获得字段列表参数 */
if (check_oci_error(errhp,
OCIAttrGet((void *)dpctx, (ub4)OCI_HTYPE_DIRPATH_CTX,
(void *)&colLst, (ub4)0,
(ub4)OCI_ATTR_LIST_COLUMNS, errhp)
) < 0)
return (-1);
/* 为了方便设置,我们定义一个结构存储字段信息 */
col[0].dtyp = SQLT_INT;
col[0].clen = 8;
strcpy(col[0].name, "ID");
col[1].dtyp = SQLT_CHR;
col[1].clen = 30;
strcpy(col[1].name, "NAME");
col[2].dtyp = SQLT_CHR;
col[2].clen = 200;
strcpy(col[2].name, "ADDR");
for (i=0; i<ncol; i++) {
/* 获取字段描述符,这个描述符是隐式获得,需要释放,否则会造成内存泄露 */
if (check_oci_error(errhp,
OCIParamGet((const void *)colLst, (ub4)OCI_DTYPE_PARAM,
errhp, (void **)&colDsc, (ub4)(i+1))
) < 0)
return (-1);
/* 设置字段的属性,字段名称 */
if (check_oci_error(errhp,
OCIAttrSet((void *)colDsc, (ub4)OCI_DTYPE_PARAM,
(void *)col[i].name, (ub4)strlen(col[i].name),
(ub4)OCI_ATTR_NAME, errhp)
) < 0)
return (-1);
/* 设置字段数据类型 */
if (check_oci_error(errhp,
OCIAttrSet((void *)colDsc, (ub4)OCI_DTYPE_PARAM,
(void *)&col[i].dtyp, (ub4)0,
(ub4)OCI_ATTR_DATA_TYPE, errhp)
) < 0)
return (-1);
/* 设置字段的数据最大长度 */
if (check_oci_error(errhp,
OCIAttrSet((void *)colDsc, (ub4)OCI_DTYPE_PARAM,
(void *)&col[i].clen, (ub4)0,
(ub4)OCI_ATTR_DATA_SIZE, errhp)
) < 0)
return (-1);
/* 在这里要释放掉字段描述符,否则下一循环获取描述符时,
* 这个描述符指向的内存就会被掩盖掉,造成内存泄露
*/
OCIDescriptorFree((void *)colDsc, (ub4)OCI_DTYPE_PARAM);
}
/* 设置完所有字段后,要把字段列表的描述符也释放掉 */
OCIDescriptorFree((void *)colLst, (ub4)OCI_DTYPE_PARAM);
/* 到这里,字段信息就设置完了,后面需要设置字段的输入值了,下一节继续 */
return (0);
}