OTL 是 Oracle, Odbc and DB2-CLI Template Library 的缩写,是一个 C++ 编译中操控关系数据库的模板库,它目前几乎支持所有的当前各种主流数据库。 OTL 使用起来比较方便,其官方网站也提供了详细的文档和例子( http://otl.sourceforge.net/otl3.htmhttp://otl.sourceforge.net/otl3_examples.htm )。

最近在项目中需要使用 OTL 调用 Oracle 存储过程,并且需要返回游标,在网上查了一下,相关的中文资料比较少,经过一番辛苦的查找和摸索,最后终于如愿达到目的。在这里把相关的经验分享给大家,如有不对的地方,欢迎拍砖。

OTL 调用 Oracle 存储过程,其官方文档中给出了相应的例子,地址是 http://otl.sourceforge.net/otl4_ex149.htm 。现节选关键部分如下:

…

otl_stream i(1,

"begin "

" my_pkg.my_proc(:f1<int,in>,:f2<int,in>, "

"         :str1<char[100],out>, "

"         :cur1<refcur,out[50]>, "

"         :cur2<refcur,out[50]>); "

"end;",

db // connect object

);

i.set_commit(0); // set stream "auto-commit" to OFF.

char str1[101];

float f1;

char f2[31];

otl_refcur_stream s1, s2; // reference cursor streams for reading rows.

i<<8<<4;

i>>str1;

i>>s1;

i>>s2;

cout<<"STR1="<<str1<<endl;

cout<<"=====> Reading :cur1..."<<endl;

while(!s1.eof()){ // while not end-of-data

s1>>f1>>f2;

cout<<"f1="<<f1<<", f2="<<f2<<endl;

}

cout<<"=====> Reading :cur2..."<<endl;

while(!s2.eof()){ // while not end-of-data

s2>>f1>>f2;

cout<<"f1="<<f1<<", f2="<<f2<<endl;

}

s1.close(); // closing the reference cursor

s2.close(); // closing the reference cursor

…

可以看出,调用存储过程和执行普通的 sql 大同小异,也是通过 otl_stream 对象绑定相关参数,不同之处有以下几点:

1 .调用存储过程 / 函数时,缓冲大小必须设置为 1 。

2 . Sql 声明时语句必须采用 ”begin …… end;” 的形式。存储过程如果位于包内,还必须带上包名。绑定参数除了声明类型、大小以外,还必须指明参数的输入输出标志。返回游标的大小代表了游标内的记录数。

3 .返回游标绑定的数据类型是 otl_refcur_stream ,就像普通的 otl_stream 一样,可以使用 while 循环读取其中的数据。游标对象使用完毕后,别忘了使用 close 方法将其关闭。

在这个过程中,有两个需要注意的地方:

1 . OTL 在输入输出参数的方向标志方面稍微有点不人性化,即要求所有的 in 、 out 与前面的逗号“ , ”之间不允许有空格、制表符等空白字符,否则就会无法识别方向标志而发生 ORA-01008 错误,并提示“并非所有变量都已绑定”。

2 .如果存储过程内存在多条执行路径,并且某些执行路径并不返回游标的情况下,就需要程序员自己判断在当前情况下是否需要接收游标。如果当前存储过程并未返回游标,而在 c++ 程序中执行了提取( >> )操作,就会发生 ORA-24338 错误 ,并提示“未执行语句句柄”。此时,如果允许的话可以通过存储过程返回的其他变量判断是否需要进行接收操作,如:

…

if(“00” == ret_code)      // 其中 ret_code 是存接收了储过程执行状态的变量

{

o >> first_cur;

o >> detail_cur;

}

…

OTL 调用存储函数和存储过程基本相似,只不过是多了一个返回值而以。格式大致如下:

…

otl_stream i(1,

"begin "

"   :rc<int,out> :=my_pkg. my_func(:f1<int,in>,:f2<int,in>, "

"         :str1<char[100],out>, "

"         :cur1<refcur,out[50]>, "

"         :cur2<refcur,out[50]> "

"                          );  "

" end; ",

db // connect object

);

int res = 0;

char str1[101];

float f1;

char f2[31];

otl_refcur_stream s1, s2; // reference cursor streams for reading rows.

i<<8<<4;

i >> res;

i>>str1;

i>>s1;

i>>s2;

…

这里也有两个需要注意的地方,一是 sql 声明时存储函数名前面的等号要用“ := ”;再就是接收输出时,首先接收函数返回值,再依次接收其他输出。其他操作同存储过程一致。关于调用存储过程 / 函数时, sql 声明的具体格式, OTL 提供了一个专门的函数create_stored_proc_call ,可以生成相应的绑定 sql 。其具体使用方法参见 http://otl.sourceforge.net/otl4_ex153.htm 。

补充一下:笔者的环境是 otl v4.0.218 OraClient11g vs2008sp1 winxp sp3 。

OTL调用存储过程/函数及注意事项的更多相关文章

  1. DAO调用存储过程问题

    相关文章:1.使用 Spring 框架调用 DB2 存储过程   2.Spring如何使用JdbcTemplate调用存储过程的三种情况   3.spring中调用存储过程,函数

  2. MySQL 存储过程 函数 routine 权限

    MySQL 存储过程 函数 routine 权限 Table of Contents 1. mysql存储过程/函数权限 1.1. 相关对象操作权限检查 1.2. 执行权限 1 mysql存储过程/函 ...

  3. jdbc调用存储过程和函数

    1.调用存储过程 public class CallOracleProc { public static void main(String[] args) throws Exception{ Stri ...

  4. java调用存储过程和函数

    以对表test进行增,删,改,查进行说明:1.新建表test create table TEST ( TID NUMBER not null, TNAME VARCHAR2(32), TCODE VA ...

  5. 转:EF调用存储过程、函数

    EF调用存储过程.函数 2014-04-02 09:12:20|  分类: ORM框架|举报|字号 订阅          一.ef4.1 codeFirst 修改表结构 增加字段等 EF code ...

  6. 【转】java调用存储过程和函数

    一.概述 如果想要执行存储过程,我们应该使用 CallableStatement 接口. CallableStatement 接口继承自PreparedStatement 接口.所以CallableS ...

  7. JDBC第二篇--【PreparedStatment、批处理、处理二进制、自动主键、调用存储过程、函数】

    这是我JDBC的第一篇 http://blog.csdn.net/hon_3y/article/details/53535798 1.PreparedStatement对象 PreparedState ...

  8. java程序调用存储过程和存储函数

    java程序调用存储过程 jdbcUtil.java文件 package cn.itcast.oracle.utils; import java.sql.Connection; import java ...

  9. oracle创建函数和调用存储过程和调用函数的例子(区别)

    创建函数: 格式:create or replace function func(参数 参数类型) Return number Is Begin --------业务逻辑--------- End; ...

随机推荐

  1. 《逐梦旅程 WINDOWS游戏编程之从零开始》笔记8——载入三维模型&Alpha混合技术&深度测试与Z缓存

    第17章 三维游戏模型的载入 主要是如何从3ds max中导出.X文件,以及如何从X文件加载三维模型到DirextX游戏程序里.因为复杂的3D物体,要用代码去实现,那太反人类了,所以我们需要一些建模软 ...

  2. Fraction to Recurring Decimal——数值处理&&哈希表

    Given two integers representing the numerator and denominator of a fraction, return the fraction in ...

  3. 很好用的谷歌字体以及Gravatar头像一键替换WordPress插件----WP Acceleration for China 插件

    WordPress总是被新上手的朋友诟病说速度慢,其实多半都要归功于谷歌字体的功劳.在应对字体这个问题的时候,大家都会有各种不同的解决方案.今天我给大家推荐一款插件,它集合了多个替代方案,可以方便的替 ...

  4. Linux:hping高级主机扫描

    https://www.aliyun.com/jiaocheng/167107.html https://blog.csdn.net/weixin_39762926/article/details/7 ...

  5. [水煮 ASP.NET Web API2 方法论](1-5)ASP.NET Web API Scaffolding(模板)

    问题 我们想快速启动一个 ASP.NET Web API 解决方案. 解决方案 APS.NET 模板一开始就支持 ASP.NET Web API.使用模板往我们的项目中添加 Controller,在我 ...

  6. CentOS7.5更改grub2菜单背景&开机动态画面

    Grub2菜单背景 红帽企业版 Linux 7 的引导装载程序是“GRUB 2”.您可以更改“GRUB 2”外观的几个部分.以下几小节将向您展示如何改变 Linux 发行版名称.菜单颜色,和背景图片. ...

  7. 利用tengine的nginx_upstream_check_module来检测后端服务状态

    nginx_upstream_check_module 是专门提供负载均衡器内节点的健康检查的外部模块,由淘宝的姚伟斌大神开发,通过它可以用来检测后端 realserver 的健康状态.如果后端 re ...

  8. Linux搭建主从数据库服务器(主从复制)

    配置主机数据库: 1.克隆linux操作系统 2.修改Linux系统主机IP地址 主机IP:192.168.247.150 从机IP:192.168.247.151 3.通过xshell连接Maste ...

  9. Mindjet Mindmanager复制文件打不开

    概述 使用Mindjet软件画思维导图,保存后得到一个后缀为mmap的文件.复制到一个新的位置,却发现新的文件打不开,导致Mindjet崩溃.这里提供一个解决方案. 解决方案 复制的文件打不开 先打开 ...

  10. HDU 6373 Pinball

    Pinball Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total S ...