当前位置: 首页 > article >正文

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);
}


http://www.kler.cn/news/283786.html

相关文章:

  • 数据结构与算法 第四天(串、数组、广义表)
  • HTTP分析
  • 高级java每日一道面试题-2024年8月30日-数据库篇-数据库的三范式是什么?
  • Java技术栈 —— Spark入门(三)之实时视频流
  • Dubbo如何传递链路追踪id?
  • 小琳AI课堂:使用ChatGPT API搭建系统(二)
  • innovus:如何让部分sink长到target insertion delay的长度
  • 关于OBI 在unity URP环境下使用的正确步骤
  • 网络编程(学习)2024.8.27
  • jQuery基础——选择器的补充方法——过滤方法、查找方法
  • python使用multiprocessing多进程通讯
  • 各种各样的正则表达式
  • 92. UE5 RPG 使用C++创建GE实现灼烧的负面效果
  • 达梦数据库-DM8 企业版安装指南
  • [java][代码] java中date格式化输出时间字符串
  • 《征服数据结构》LFU缓存
  • Vatee万腾平台:打造企业智能化转型的坚实后盾
  • 【Android】UIMode
  • fpga图像处理实战-双三次插值算法
  • Jmeter提取token并设置为全局变量
  • 聊聊STM32 MCU的BOOT0和BOOT1引脚
  • 浅谈Vue3和React18
  • 六个方面探讨企业为何迫切需要替换FTP
  • PyQt 迁移到 PySide
  • WPF ToolkitMVVM RelayCommand
  • 探究:Elasticsearch 文档的 _id 是 Lucene 的 docid 吗?
  • DNN学习平台(GoogleNet、SSD、FastRCNN、Yolov3)
  • C# 自动化抢购脚本:基于商品链接的实现方案
  • 【杂谈】新能源和智能车
  • 在docker中安装skywalking + es