说明
该文档说明的是4.0版本的ORACLE/ODBC和DB2-CLI模板库(OTL)。OTL4.0(后面简称OTL)模板库是基于C++的模板的。
OTL4.0是组合了C++的模板框架和OTL适配器。框架是一个简单的OTL_stream的概念,OTL适配器则是一个基于数据库API的经量级的类库,并且作为参数传给OTL的框架参数。
OTL4.0仅通过otl_stream、otl_connect、otl_exception、olt_long_string和几个简单的ORACLE数据库的从模板框架和OTL适配器派生的的table_container类便包含了所有其他的C++数据库访问类库的所有优点。
因为OTL的代码里面是直接调用数据库的API操作的,所以相比于原生的数据库API操作,OTL的性能上仅低10-15%左右,并且还能良好的支持多进程。OTL4.0因为专业与精简的类库,具有非常高的通用性。
OTL是ANSI编码的,与STL具有非常紧密的联系。并且支持STL的string在otl_stream里面;还整合了ACE通过支持ACE_TString。
OTL支持的数据库有,ORACLE7.3以上的版本、DB2 UDB LUW / Zos、MS SQL SERVER 2005/2008、Informix 11、TimesTen 7以上版本、SAP-MAX/DB、ODBC 2.5和3.0(通过unixodbc或iODBC)、Sybase、MySql、PostgreSQL、EnterpriseDB、SQLite、MS ACCESS、Firebird等等,后续还会添加更多支持。
在过去的一段时间里面,OTL在字符集方面作了一些修改。添加了64位平台的支持,现在OTL已经开始同时支持32和64位平台。并且在数据库的API或ODBC支持的情况下对ORACLE来讲还支持UTF-8和UTF16字符集,对其他的数据库则支持UTF-16字符集。
OTL流的概念
任何的SQL语句、SQL语句块或存储过程,都是通过输入与输出变量进行处理参数与结果的。如:
例1:一个SELECT语句把标量的输入变量作为WHERE子句部分的条件;同时SELECT部分则定义了输出的字段,并且在结果集为多行的情况下还是一个VECTOR结构。
例2:一个INSERT语句把数据写入数据库中,同样需要输入数据。UPDATE也是同样的道理。
例3:一个DELETE语句从表中删除数据,删除的条件同样需要通过参数输入。
例4:一个存储过程可能同时具有输入与输出参数。通过存储过程的参数都是标量,但某些特殊情况下ORACLE的存储过程还可以返回一个游标、MS SQL SERVER还可以返回一个结果集。
例5:一个多功能的SQL语句块则有可能具有标量或矢量的输入与输出参数。
专业的程序里面往往有大量的SQL操作,如大量的INSERT/UPDATE/SELECT/DELETE等。所以参数对于SQL语句来讲,都可以理解为VECTOR的类型。
下面的图示表示的非常清楚。对于任何的SQL语句或语句块存储过程等,这些SQL都可以作为一个黑盒子一样。它们的输入与输出总是具有VECTOR类型。
为什么不把SQL语句与数据(输入或输出参数)整合在一起?而是通过多个不同的结构来包装SQL语句与数据呢?OTL通过otl_stream来回答这个问题。
SQL语句在执行的时候,通过otl_strea对数据进行操作,otl_stream是一个缓冲流,它包括输入与输出两个缓冲区。输入缓冲区用来存放输入参数,输出缓冲区用来存放输出参数。
C++流总是通过重载 >> 和 << 两个操作符来处理输入与输出数据,otl_stream同样也重载了这两个符号用来处理输入与输出数据。
OTL的流与C++的流类似。一个SQL语句或存储过程打开的时候通过一个普通的缓冲流,OTL的逻辑SQL语句部分还是保留。OTL的流把输入与输出缓冲区分开处理。
OTL流里面有个刷新的函数,当缓冲区满的时候或是重新读取或写入数据的时候,就通过该刷新操作把重新刷新缓冲区的数据。更重要的是OTL的流具有相当简单的接口,对于熟悉C++流的你来说,只要记住简单的几个操作即可。
在OTL流内部有一个简单的变量解析器。所以不需要绑定变量的时候指定变量类型与占位符,所有这些都在OTL流内部动态的处理。OTL流仅需要打开进行读和写。
OTL流可能会抛出otl_exceptionr的异常,所以为了避免程序core down需要在处理OTL流的时候,用try…catch…块把相关代码包含起来。
OTL流的数据处理是自动的。当所有的输入变量全部定义后,它就自动的触发SQL去执行,并把输出填到输出缓冲区里面。此时输出就可以去缓冲区里面读取数据。如果缓冲区里面的数据满了后,还有数据未读出,则等等读取缓冲区数据后,再去取其他部分的数据(如缓冲区只能容1000行数据,但某次SELECT取出了2000条数据,则先取出1000条后,如果缓冲区数据被程序取出后,OTL再自动的去取另外的1000条数据填进缓冲区里面)。
OTL的类
相比于传统的C++类库而言,OTL更像是一个代码容器,里面复杂,但对外的接口简单。OTL在处理程序方面受到了STL的影响。
OTL有一个模板框架,它实现了otl_stream的概念。该框架由模板类和内联函数组成。模板类把普通的类型作为参数,这些参数的类型提供了对数据库API的详细操作。
对于已有的数据库API,OTL提供如下的数据库API支持:
- Oracle Call Interface for Oracle 7/8/8i /9i/10g/10gR2/11g (OCI7/8/8i/9i/10g/10gR2/11g)
- Open Data Base Connectivity (ODBC)
- MS SQL Server 2005/2008's SQL Native Client (SNAC)
- DB2 Call Level Interface (CLI)
- Informix CLI
- TimesTen CLI
- SAP DB CLI
OTL适配器通过经量级的封装数据库API,并且由于OTL适配器是直接的与模板框架进行通信,所以OTL能够提供近乎直接调用数据库API的性能。
OTL的模板框架提供了如下的OTL类:
- otl_stream
- otl_connect
- otl_exception
- otl_long_string
otl_stream
otl_stream是具体实现otl_stream_concept的类。任何的SQL语句、SQL语句块和存储过程都能通过otl_stream进行处理。
传统的数据库API处理SQL语句的时候,需要绑定变量与占位符,因此,程序员需要定义变量、解析SQL语句、调用绑定占位符的函数、把变量绑定到占位符上、执行SQL、读取输出的变量等等。如此循环。以上所有的这些操作在OTL里面的otl_stream类里面都是自动处理的,otl_stream类提供了与数据库交互自动化最大性能。该性能仅取决于一个参数-缓冲区大小。缓冲区是用于存放SQL执行过程中的逻辑行数。
注:在timesten7.0.2或以上版本的数据库中,定义了OTL_TIMESTEN_UNIX或OTL_TIMESTEN_WINDOWS宏的时候,缓冲区大小可以设置为0。此时表示默认使用数据库的最佳缓冲区大小。一般情况下是一个元素大小。具体更多信息请参考数据库的手册。
一个SQL语句在otl_stream里面至少需要一个输入或输出占位符,对于没有占位符的SQL语句,它将被作为常量的SQL语句作为另一种方式执行。
从OTL4.0.115版本开始后,缓冲区大小的类型为整形,以前的版本全是短整形。如果需要支持旧版本的代码,请在编译代码前添加定义OTL_STREAM_LEGACY_BUFFER_SIZE_TYPE宏。
otl_stream类有如下的公共方法:
序号 | 函数名 | 说明 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 | otl_stream(…)
| 仅ORACLE 7/8/9/10/11版本 构造函数。 该构造函数创建一个otl_steram对象,并且调用open()函数。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2 | otl_stream(…)
| 仅ODBC/DB2 CLI 构造函数,该构造函数创建一个otl_stream对象,并且调用open()函数。 在ODBC和DB2 CLI下面对该对象还定义了如下两个常量: otl_explicit_select:指定该流为一个简单的SELECT语句流; otl_implicit_select:指定该流为一个返回结果集的流; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3 | void open(…)
| 仅ORACLE 7/8/9/10/11版本 该函数打开(执行)SQL语句,总共分为如下:解析SQL语句、在流内部为输入输出变量分配内存空间、自动绑定变量到对应的占位符。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4 | void open(…)
| 仅ODBC/DB2 CLI 该函数打开(执行)SQL语句,总共分为如下:解析SQL语句、在流内部为输入输出变量分配内存空间、自动绑定变量到对应的占位符。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5 | int eof() | 测试流里面是否所有的数据全被读取出来,该函数与C++的IO流里面的eof()函数同理。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
6 | int setBufSize(const int buf_size) | 设置缓冲区大小。 该函数仅是对后续的otl_connect::operator>>(otl_stream&)操作保存(新建)一个新的缓冲区。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
7 | void flush() | 刷新输出流缓冲区。 它实际上的操作是通过执行流里面的SQL语句来填充输出缓冲区。流在缓冲区满的情况下自动的进行刷新操作。 该函数与C++的IO流的flush()同理。 如果在设置了auto-commit标识的情况下,在刷新了输出缓冲区后,也就会自动的进行一次事务提交。更详细的解释请见set_commit() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
8 | void flush(…)
| 在OCI 8/8i/9i/10g/11g的版本里面还带有一个带两个参数的flush()版本的函数。该函数有两方面的作用: 1、 对大数据量的操作更高效 2、 能够识别(发现)出重复的数据,并抛出异常 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
9 | int get_auto_commit_flag() | 取得自动提交标识。 1:表示自动提交标识已设置 0:表示自动提交标识未设置 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
10 | int get_stream_type() | 仅ORACLE 7/8/9/10/11版本 取得流的类型。 返回的类型由如下的整形常量: otl_no_stream_type—流还未通过SQL进行实例化 otl_select_stream_type—流是一个简单的SELECT语句的流 otl_inout_stream_type—流是通过一个带有输入输出参数的匿名的SQL块进行实例化的,还有可能是一个存储过程。 otl_refcur_stream_type—流是通过一个SQL语句块进行实例化的,该SQL块返回的是一个游标。在这种流的情况下,只能有输入参数,输出参数一定是一个游标。 otl_constant_sql_type—该类型本只能在使用create_stored_proc_call()里面使用,然而它代表了一种流类型。 在create_stord_proc_call()里面它本义也是指不带有参数的,而且它必须通过otl_cursor::direct_exec()执行。 otl_mixed_refcur_stream_type—只由create_stoerd_proc_call()实例的类型。它能够带有输入或输出参数,并且一定有返回一个游标。 如果create_stored_proc_call()的sql_stm参数设定了的情况下,流的缓冲区大小必须设置为1,并且必须通过otl_refcur_stream去读取游标的数据。更详细的请见例:153 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
11 | static void create_stored_proc_call(…)
| 仅ORACLE 7/8/9/10/11版本 不能定义在OTL_UNICODE宏下面实现。 通过存储过程名去实现一个兼容的otl_stream流。 这是个静态的函数,意图去实现调用oracle的存储过程。 为了能够获取到存储过程的参数和类型,该函数使用ORACLE的系统数据字典。可能会抛出32014、32015、32016的OTL异常。 该函数能够调用下列的函数或存储过程: 1:当前或指定用户名下面的SQL包的存储过程或函数;当前或指定用户名下面的全局的存储过程或函数。 2:公共或私有同义词下面的SQL包的存储过程或函数;公共或私有同义词下面的全局的存储过程或函数。 3:没有重载(同名)的存储过程或函数。 4:带有标量的输入或输出参数,或带有输出游标的存储过程或函数。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
12 | void clean(const int clean_up_error_flag = 0) | 在不刷新缓冲区的情况下,清理掉缓冲区里面的内容。 如果clean_up_error_flag参数设置为1,那么除了清掉缓冲区内容的同时,还清理掉流里面抛出的异常信息。 详细请见例:65、66、67.该参数的意义在于提供一个不需要关闭流的情况下可以重新返回数据库的相关错误信息。 在4.0.6及以后的版本中,该函数还能中断一个正在执行中的SQL语句,并且清空错误信息。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
13 | void rewind() | 重新处理一个流(恢复一个流到初始状态)。 如果该流没有参数,则强制该流的执行。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
14 | operator int() | 把流转换为int类型的重载操作符。 它返回!eof()的结果状态。它能够被用在一直循环里面,如下: while(s>>f1>>f2){ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
15 | void cancal() | 仅ODBC / DB2 CLI。 中止一个正在处理中的SELECT语句或是存储过程。 而且对于一个线程中正在运行的,另一个线程能异步的中止该正在执行中的流。 具体的中止操作取决于数据库层的API函数。 并且错误信息也是由数据库层抛出。 OCI8/8i/9i/10g也有一个相类似的函数otl_connect:cancel(),但是与DB2 CLI确是不同的。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
16 | bool get_next_diag_rec(…)
| 仅支持ODBC。 必须定义OTL_ODBC_SQL_STATEMENT_WITH_DIAG_REC_OUTPUT宏。 该函数是用来通过MS SQL SERVER的BACKUP/DBCC命令获取动态的记录。函数内部实际是调用SQLGetDiagRec()函数。 记录的索引从1开始计数。 函数能自动的增加索引。 更详细资料请见例:688、689 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
17 | SQLHSTMT get_stm_handle() | 仅ODBC适用 必须定义OTL_ODBC_SQL_STATEMENT_WITH_DIAG_REC_OUTPUT宏。 该函数用来返回底层的ODBC句柄。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
18 | int is_null() | 测试是否stream返回一个空值 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
19 | void set_lob_stream_mode(const bool mode = false) | 设置log_stream_mode标识。 该标识通知流使用otl_lob_stream操作。 在OCI8上面该函数不是必须的,不过在ODBC/DB2 CLI或是otl_stream_read_iterator一起使用的时候,必须设置该值。 或是在代码里面添加多数据库支持的时候,必须调用该函数。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
20 | long get_rpc() | 返回数据库本次操作返回的记录行数。 返回的数据由INSERT/UPDATE/DELETE语句返回的操作行数; 对于INSERT操作,它返回的是小于或等于缓冲区大小。对于UPDATE或DELETE语句,它取决于实际更新或删除的行数。 在4.0.6及以后的版本中,该函数对于SELECT语句返回的是累计操作的行数。 对于ORACLE和DB2 CLI或ODBC,该函数返回值有些不同。如对于出错状态的情况下,ORACLE返回的是实际成功的行数,而对于DB2或ODBC它返回的总是0. 结论:对于想兼容所有的数据库来说,该函数并不适用于所有的数据库。但对于ORACLE的不同版本的数据库来说,它还是通用的。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
21 | void set_commit(int auto_commit = 0) | 设置流的auto-commit标识。 当流的输出缓冲区刷新的时候,就会自动进行事务提交操作。 如果想避免自动提交,请设置自动提交标识为false。 该自动提交标识与数据库的自动提交是两码事,该自动提交标识只是OTL自己的自动事务提交标识。 实际上设置为非自动提交还是非常方便的,在这种情况下,就可以使用otl_nocommit_stream类。 otl_nocommit_stream类是一个直接继承otl_stream类的子类,仅是关闭了自动提交标识。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
22 | void set_flush(const bool auto_flush = true) | 设置流的自动刷新标识。 默认值为真。 实际上,流的析构函数试图进行刷新操作。 自动刷新标识可以通过该函数进行关闭。 如果自动刷新标识被关闭后,流就必须通过otl_stream::close()或otl_stream::flush()操作来强制刷新流,因为就算流的脏标志为真的情况下流的析构函数也不会去刷新缓冲区。 该函数仅是禁止析构函数里面的自动刷新功能。 对于一般的缓冲区提交不能禁止。 例如缓冲区满的情况下还是会自动进行刷新操作。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
23 | otl_var_desc * describe_out_vars(int & desc_len) | 一组用来分析流的输入或输出绑定变量的函数。函数返回一个otl_var_desc结构体的指针。 otl_var_desc类类型如下:
该函数用来取得输出变量的属性,参数desc_len返回的是otl_var_desc结构体大小。 如果流里面没有输出参数,则返回0。 如果有参数同时为输入和输出参数,它返回输出参数部分。 流的输出参数指的是取出流的部分。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
24 | otl_var_desc * describe_in_vars(int & desc_len) | 该函数用来取得输入变量的属性,参数desc_len返回的是otl_var_desc结构体大小。如果流里面没有输入参数,则返回0。 如果有参数同时为输入和输出参数,它返回输入参数部分。 流的输入参数指的是输入流的部分。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
25 | otl_var_desc * describe_next_out_var() | 取得下一步输出变量。“下一个”指的是从流中读取了以后,下一个读出来的输出变量。比如调用了otl_stream::operator<<()后,有时候我们想要知道下一步输出变量的类型。如果没有下一个变量的时候,函数返回0. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
26 | otl_var_desc * describe_next_in_var() | 取得下一步输入变量。“下一个”指的是从往流中写入了以后,下一个写入的输入变量。比如调用了otl_stream::operator<<()后,有时候我们想要知道下一步输入变量的类型。如果没有下一个变量的时候,函数返回0. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
27 | (1) void close() | 关闭流。 该函数与C++里面的流具有相同的概念。 该函数有两个版本,一个是普通的版本,另一个是在定义了OTL_STREAM_POOLING_ON宏下的另一个版本。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
28 | (2) void close(const bool save_in_stream_pool = true) | 定义了OTL_STREAM_POOLING_ON宏情况下使用。 save_in_stream_pool标志是一个初始化标志。 当它设置为真的时候,在定义了OTL_STREAM_POOLING_ON宏的情况下,关闭一个流,并非真正的把流关闭了,而是把该流放到一个流缓冲池下面。 如果后续还要接着使用该流,那直接调用缓冲池里面的流就可以,而不用重新再新建一个流。 如果标志设置为假,那么关闭流的时候就是真正关闭了流。 在对于某些流需要消耗大量系统资源的情况下,该参数非常有用。 因为可以减少分配、删除流资源的时间而提高性能。 更详细的请见例:113、114、115 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
29 | int good() | 测试流是否是打开的。 与C++里面的流打开具有相同的功能。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
30 | otl_column_desc * describe_select(int & desc_len) | 取得流的输出变量的字段列表。 仅对下列有效:
函数返回otl_column_desc结构体的指针。 otl_column_desc类型如下:
OTL定义了如下的类型与相应的数据库类型相对应:
除了返回结构体的指针外,该函数还返回一个desc_len的参数。 该参数表示返回的字段列表的长度。 该函数返回的结构的指针不用用户删除,流里面在析构的时候会处理删除任务。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
31 | void reset_to_last_valid_row() | 当OTL抛出“incompatible data type in stream operation”异常的时候,该异常为OTL内部的异常,它在流里面的SQL执行之前抛出,此时reset_to_last_valid_row()函数就能把输出缓冲区恢复到最后一个正确的位置。这个时候就能正确的调用flush()操作。如下: otl_stream str ... | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
32 | otl_stream & operator>>(unsigned char * s) | 从流里面读取数据 当定义了OTL_UNICODE的时候,它返回的是以NULL结尾的双字节的字符串。否则返回的是单字节的字符串。 |
33 | otl_stream & operator>>(otl_long_unicode_string & s) | 在定义了OTL_UNICODE或OTL_UNICODE_CHAR_TYPE宏情况下,返回UNICODE的LOB类型 | |||||||||||||||||||||||||||||||||
34 | otl_stream & operator>>(OTL_UNICODE_CHAR_TYPE&c) | 在定义了OTL_UNICODE或OTL_UNICODE_CHAR_TYPE宏情况下,返回UNICODE的字符类型 | |||||||||||||||||||||||||||||||||
35 | otl_stream operator>> (OTL_UNICODE_CHAR_TYPE * s) | 在定义了OTL_UNICODE或OTL_UNICODE_CHAR_TYPE宏情况下,返回UNICODE的字符串 | |||||||||||||||||||||||||||||||||
36 | otl_stream & operator>> (OTL_UNICODE_STRING_TYPE & s) | 在定义了OTL_UNICODE或OTL_UNICODE_CHAR_TYPE/OTL_UNICODE_STRING_TYPE宏情况下,返回UNICODE的string类型,能够很好的读取大数据字段类型,如TEXT类型等。 | |||||||||||||||||||||||||||||||||
37 | otl_stream & operator>>(char & c) | 返回单字节的字符 | |||||||||||||||||||||||||||||||||
38 | otl_stream & operator>>(undigned char & c) | 返回单字节的无符号字符 | |||||||||||||||||||||||||||||||||
39 | otl_stream & operator>>(char * s) | 返回单字节的字符串类型 | |||||||||||||||||||||||||||||||||
40 | otl_stream& operator>>(unsigned char* s); | 返回无符号的单字节字符串类型 | |||||||||||||||||||||||||||||||||
41 | otl_stream& operator>>(otl_long_string& s); | 返回LOB类型 | |||||||||||||||||||||||||||||||||
42 | otl_stream& operator>>(std::string& s); | 必须定义OTL_STL宏。 读取流中的string类型 | |||||||||||||||||||||||||||||||||
43 | otl_stream& operator>>(ACE_TString& s); | 必须定义OTL_ACE。 读取流中的ACE_TString类型。 | |||||||||||||||||||||||||||||||||
44 | otl_stream& operator>>(USER_DEFINED_STRING_CLASS & s); | 必须定义USER_DEFINE_STRING_CLASS和OTL_USER_DEFINED_CLASS_ON宏。 读取用户自定义的与string类型兼容的类型。 | |||||||||||||||||||||||||||||||||
45 | otl_stream& operator>>(int& n); | 读取32位有符号整型 | |||||||||||||||||||||||||||||||||
46 | otl_stream& operator>>(unsigned& u); | 读取32位无符号整武师 | |||||||||||||||||||||||||||||||||
47 | otl_stream& operator>>(short& sh); | 读取16位短整型 | |||||||||||||||||||||||||||||||||
48 | otl_stream& operator>>(long int& l); | 读取长整型(具体长度由编译器决定) | |||||||||||||||||||||||||||||||||
49 | otl_stream& operator>>(float& f); | 读取4字节长度的浮点型 | |||||||||||||||||||||||||||||||||
50 | otl_stream& operator>>(double& d); | 读取8字节长度的浮点型 | |||||||||||||||||||||||||||||||||
51 | otl_stream& operator>>(OTL_BIGINT& d); | 在定义了OTL_BIGINT的情况下。 对于不支持bigint的ODBC来说,该操作能将一个数字串转换为64位的有符号整型。 必须定义OTL_STRING_TO_BIGINT/OTL_BIGINT_TO_STRING。 | |||||||||||||||||||||||||||||||||
52 | otl_stream& operator>>(otl_datetime& dt); | 读取流中的时间信息 | |||||||||||||||||||||||||||||||||
53 | otl_stream& operator>>(otl_XXX_tab<…>& tab); | 通过OCI来读取SQL语句中的表信息 | |||||||||||||||||||||||||||||||||
54 | otl_stream& operator>>(otl_lob_stream& lob); | 把CLOB/BLOB/TEXT/IMAGE类型读取到otl_lob_stream类型里面 | |||||||||||||||||||||||||||||||||
55 | otl_stream& operator>>(otl_refcur_stream& refcur); | 把游标的信息读取到otl_refcur_stream类型里面。 | |||||||||||||||||||||||||||||||||
56 | otl_stream& operator<<(const unsigned char* s); | 往流中写入信息。 往流中写入一个以NULL结尾的字符串。 如果定义了OTL_UNICODE,则是双字节字符串。 | |||||||||||||||||||||||||||||||||
57 | otl_stream& operator<<(otl_long_unicode_string& s); | 往流中写入UNICODE LOB类型 | |||||||||||||||||||||||||||||||||
58 | otl_stream& operator<<(const OTL_UNICODE_CHAR_TYPE& c); | 在定义了OTL_UNICODE_CHAR_TYPE宏的情况下,往流中写入一个UNICODE字符 | |||||||||||||||||||||||||||||||||
59 | otl_stream& operator<<(const OTL_UNICODE_CHAR_TYPE* s); | 往流中写入一个UNICODE字符串 | |||||||||||||||||||||||||||||||||
60 | otl_stream& operator>>(const OTL_UNICODE_STRING_TYPE& s); | 在定义了OTL_UNICODE/OTL_UNICODE_CHAR_TYPE/OTL_UNICODE_STRING_TYPE宏的情况下,把一个字符串写入到流中。 (可以是大对象) | |||||||||||||||||||||||||||||||||
61 | otl_stream& operator<<(const char c); | 往流中写入一个字符 | |||||||||||||||||||||||||||||||||
62 | otl_stream& operator<<(const unsigned char c); | 往流中写入一个无符号的字符 | |||||||||||||||||||||||||||||||||
63 | otl_stream& operator<<(const char* s); | 往流中写入一个以NULL结尾的字符串 | |||||||||||||||||||||||||||||||||
64 | otl_stream& operator<<(const unsigned char* s); | 往流中写入一个以NULL结尾的无符号的字符串 | |||||||||||||||||||||||||||||||||
65 | otl_stream& operator<< (const otl_long_string& d); | 往流中写入LOB类型对象 | |||||||||||||||||||||||||||||||||
66 | otl_stream& operator<<(const std::string& s); | 在定义了OTL_STL宏的情况下,往流里面写入一个STL的string类型。 | |||||||||||||||||||||||||||||||||
67 | otl_stream& operator<<(const ACE_TString &s); | 在这、定义了OTL_ACE宏的情况下,往流中写入一个ACE_TString类型。 | |||||||||||||||||||||||||||||||||
68 | otl_stream& operator<< (const USER_DEFINED_STRING_CLASS &s); | 在定义了USER_DEFINED_STRING_CLASS和OTL_USER_DEFINED_CLASS_ON宏的情况下,往流中写入一个用户自定义的字符串类型 | |||||||||||||||||||||||||||||||||
69 | otl_stream& operator<<(const int n); | 往流中写入一个有符号的整型 | |||||||||||||||||||||||||||||||||
70 | otl_stream& operator<<(const unsigned u); | 往流中写入一个无符号的整型 | |||||||||||||||||||||||||||||||||
71 | otl_stream& operator<<(const short sh); | 往流中写入一个短整型 | |||||||||||||||||||||||||||||||||
72 | otl_stream& operator<<(const long int l); | 往流中写入一个长整型 | |||||||||||||||||||||||||||||||||
73 | otl_stream& operator<<(const float f); | 往流中写入4字节长度的浮点型 | |||||||||||||||||||||||||||||||||
74 | otl_stream& operator<<(const double d); | 往流中写入8字节长度的浮点型 | |||||||||||||||||||||||||||||||||
75 | otl_stream& operator<<(const OTL_BIGINT d); | 在定义了OTL_BIGINT的情况下。 对于不支持bigint的ODBC来说,该操作能将一个数字串转换为64位的有符号整型。 必须定义OTL_STRING_TO_BIGINT/OTL_BIGINT_TO_STRING。 | |||||||||||||||||||||||||||||||||
76 | otl_stream& operator<<(const otl_null &n); | 往流中写入NULL值。 OTL定义了一个匿名的NULL类,如下: class otl_null { public: otl_null(); ~otl_null(); }; | |||||||||||||||||||||||||||||||||
77 | otl_stream& operator<<(const otl_datetime& dt); | 往流中写入日期/时间类型。 OTL定义了自已的一个otl_datetime类,如下:
fraction/frac_precision两个成员是由数据库决定的。 具体数据库支持的精度不一样,该两个成员变量值也不一样。 | |||||||||||||||||||||||||||||||||
78 | otl_stream& operator<<(const otl_XXX_tab<…>& tab); | 往流中写入SQL的表信息 | |||||||||||||||||||||||||||||||||
79 | otl_stream& operator<<(otl_lob_stream& lob); | 往流中写入otl_lob_stream对象 | |||||||||||||||||||||||||||||||||
80 | void set_all_column_types (const unsigned int amask=0); | 设置一组输出字段的类型。 可以有如下设置: otl_all_num2str otl_all_date2str otl_all_num2str | otl_all_date2str | |||||||||||||||||||||||||||||||||
81 | void set_column_type (const int column_ndx, const int col_type, const int col_size=0); | 设置输出字段的类型。 column_ndx索引为输出字段的相对位置,如1、2、3. col_type是由OTL定义的一组类型。 col_size是指用来存放新的类型的长度,该长度只对otl_var_char类型有效,对于数值类型能自动计算得出。 该函数能被简单的SELECT语句、带游标的SELECT语句和返回结果集的SELECT语句调用。 该函数里面的类型组合如下:
该函数强烈要求限制使用,只有在那些确实因为数值容纳不下的情况下,才允许使用otl_var_char进行转换 | |||||||||||||||||||||||||||||||||
82 | int get_dirty_buf_len(); | 返回流的缓冲区里面脏数据的行数。 所谓的脏数据,指的是对于缓冲区大于1的时候,当执行SQL语句的时候,缓冲区未被填满的情况下,已经使用了的缓冲区条数。 如缓冲区为100条记录,在执行某SELECT语句后,取出30条数据,那么缓冲区此时不会被刷新,缓冲区里面有30条数据,执行此函数后就返回30。 如果缓冲区长度被设置为1后,该函数总是返回0.因为如果缓冲区为1后,每次取出记录都会填满缓冲区,此时缓冲区被填满后就会自动刷新,所以缓冲区里面未被刷新的数据总是0条,所以总是返回0。 该函数同样可以返回SELECT语句的游标或结果集缓冲区里面的脏数据。 对于其它的(非SELECT/UPDATE/DELETE/UPDATE)SQL语句块或存储过程,该函数未定义。 | |||||||||||||||||||||||||||||||||
83 | int get_prefetched_row_count(); | 返回SELEC语句、有结果集的存储过程或ORACLE的游标的累计的结果行数。 而对于其他的存储过程则总是返回0. 如:对于某SELECT语句,第一次执行返回50,第二次执行返回50,第三次执行结果返回23,那么执行该函数时候,依次返回的的结果是50、100、123。 | |||||||||||||||||||||||||||||||||
84 | void skip_to_end_of_row(); | 把读取流的指针定位到当前行的末尾。 以便下次读取流的时候,又从逻辑行的第一列开始读取。 | |||||||||||||||||||||||||||||||||
85 | void check_end_of_row(); | 检测是否到达行的末尾。 如果没有到达行的末尾,该函数抛出END_OF_ROW check failed异常。 | |||||||||||||||||||||||||||||||||
86 | otl_stream& operator>> (otl_stream& (*pf) (otl_stream&)); | 该函数调用(*pf)流函数(check_end_of_row())。 常用法如下: s>>f1>>f2>>endr; | |||||||||||||||||||||||||||||||||
87 | otl_stream& operator<< (otl_stream& (*pf) (otl_stream&)); | 同上,把输出定义为输入。 |
声明绑定变量
本章节将详细的说明如何在otl_stream流里面声明绑定变量。
SQL语句、SQL语句块或存储过程在程序里面使用的时候总是带有占位符。OTL里面带有一个小的解析器用来解析这些占位符,并且在内部进行变量的内存分配操作。
在ORACLE里面占位符的表示方法与其他数据库不同,在ORACLE里面的占位符是通过带有冒号的前缀来表示的,如::f1/:supervisor_name/:employee_id等,并且同一个占位符可能在同一个SQL语句里面使用多次。
在ODBC或DB2 CLI里面,占位符则是通过问号来表示的。如:
INSERT INTO TABLE_NAEM VALUES(?,?,?,?).
在OTL 2.0/ODBC版本里面仍然采用了位置名的占位符。如:
INSERT INTO TABLE_NAME(:1<INT>,:2<INT>,:3<INT>,:4<INT>);
在这里,数字被转换为问号。
在OTL4.0里面仍然支持上面的数字占位符。但是4.0版本里面还有名字占位符,因此推荐两种都可以使用。但是有一点不同的是,在4.0的名字占位符使用的时候,对于同一个SQL语句,里面的占位符不能同名使用。
ORACLE传统的名字占位符,后面都会扩展带有字段的类型信息,如:
INSERT INTO TABLE_NAME VALUES(:EMP_ID<INT>);
这样一次性把占位符信息定义完全,程序里面就不用再去声明宿主变量和单独调用绑定函数。对于标量的变量来说,容纳一行足够了。但是在OTL里面,它把占位符进行了扩展。下面的类型就是对扩展的占位符相对应的表:
序号 | 类型 | OTL扩展类型 | |||||||||||||||
1 | bigint | 64有符号整型。 它被用在MS SQL SERVER/DB2/MYSQL/POSTGERSQL等数据库上,表示这些数据库上原BIGING类型。ODBC和DB2 CLI是在原生API基础上已经支持了64位的BIGINT类型,所以OTL也是如此。 但对于32位的OCIx来讲,它们并不支持64位长整型,像这种情况下,OTL提供了OTL_BIGINT,OTL_BIGINT_TO_STRING,OTL_STRING_TO_BIGINT宏来帮助在BIGINT与STRING类型之间作转换。 它把BIGINT转换为VHAR[]类型来存储。 64位的OCI在64位的编译平台下面,是支持BIGINT的,但它需要定义OTL_ORA_MAP_BIGINT_TO_LONG宏来支持。 OCI11.2版本里面开始支持BIGINT,所以只需要定义OTL_BIGINT和OTL_ORA11G_R2就可以啦。 | |||||||||||||||
2 | blob | 针对ORACLE的8、9、10、11版本里面的BLOB类型。 | |||||||||||||||
3 | char[length] otl 4.0.118及以上版本 char(length) | 以NULL结尾的字符串类型。 最大长度取决于数据库。 对ORACLE来说是332545,对ODBC来说它取决于数据库与ODBC驱动,对DB2 CLI来说大于2.在定义了OTL_UNICODE宏的情况下,它是双字节的以NULL结尾的字符串。实际上使用的时候会把最后一个字符写为结尾。 如想存储数据库里面VARCHAR(10)长度的字符串的时候,必须定义为11位(或12位UNICODE)。 对于未定义长度的CHAR类型,OTL会抛出一个异常信息。如下: "INSERT INTO test_tab VALUES(:f1<int>,:f2<char>)" | |||||||||||||||
4 | charz | 在ORACLE7、8、8I、9I、10G的时候等同于CHAR[]。 仅被用于数据库里类型为CHAR[]的时候。 charz实际上是用来解决“PLS-00418:array bind type must match PL/SQL table row type”错误的。 在OCI内部对VARCHAR2/CHAR都能匹配的很好,只是对CHAR[]必须通过CHARZ来支持。 | |||||||||||||||
5 | clob | 对ORACLE8、9里面的CLOB/NCLOB | |||||||||||||||
6 | db2date | 对应DB2的DATE类型。 它仅用于DB2数据库的DATE类型占位符。 | |||||||||||||||
7 | db2time | 对应DB2的TIME类型。 它仅用于DB2 CLI或DB2 ODBC时候TIME的占位符。 同时它需要otl_datetime类的支持。 详细见例:91. | |||||||||||||||
8 | double | 8字节长度的浮点数 | |||||||||||||||
9 | float | 4字节长度的浮点数 | |||||||||||||||
10 | int | 32位有符号整型 | |||||||||||||||
11 | long | 对OCIx: 在32位平台或LLP64位的WINDOWS平台上为32位有符号的整型。 在LP64位的64位编译器平台上(XNUX)平台上为64位有符号整型。 对ODBC: 32位平台上为32位有符号整型。 对某些ODBC驱动下是64位有符号整型。 对于标准的ODBC驱动来说,SQL_C_LONG是32位的,但某些驱动把它定义为64位。 如果你想把它关联为64位,你需要定义OTL_MAP_LONG_TO_SQL_C_SBIGINT宏。 对DB2 CLI: 所有平台都为32位有符号整型。 如果你想把它关联到64位,你需要定义OTL_MAP_LONG_TO_SQL_C_SBIGIN宏。 LONG类型在不同的平台(WIN或LINUX)平台上,或是不同的数据库之间并不是通用的。 但是如果你的代码只是在同一个平台或同一个数据库下面,LONG还是可用的。 | |||||||||||||||
12 | ltz_timestamp | 对ORACLE 9i里面的带有本地时区的TIMESTAMP类型。 必须定义OTL_ORA_TIMESTAMP宏,使用otl_datetime类。 | |||||||||||||||
13 | nchar[length] | 仅在oracle 8/9/10g,在定义了OTL_UNICODE或OTL_ORA_UTF8宏的情况下,在设置了otl_connect::set_character_set(SQLCS_NCHAR)的时候等同于char[]。 仅用于在同一个SQL语句里面同时使用了VARCHAR2/CHAR和NVARCHAR2/NCHAR的时候使用。 | |||||||||||||||
14 | nclob | 仅在oracle 8/9/10g,在定义了OTL_UNICODE或OTL_ORA_UTF8宏的情况下,在设置了otl_connect::set_character_set(SQLCS_NCHAR)的时候等同于clob。 仅用于在同一个SQL语句里面同时使用了CLOB和NCLOB的时候使用。 | |||||||||||||||
15 | raw[length] | ORACLE7/8/9/10里的raw/long raw; ODBC里的SQL_BINARY(BINARY 在MS SQL/SYBASE 15/MYSQL;CHAR(XXX)BYTE在SAP/MAX DB);SQL_VARBINARY(VARBINARY在MS SQL/SYBASE 15/MYSQL; BYTEA在POSTGRESQL,VARCHAR(XXX)BYTE在SAP/MAX DB)。 对于这种类型的字段还可以通过otl_long_string来读取。 具体的长度取决于具体的数据库。 其他可以见宏 OTL_MAP_SQL_VARBINARY_TO_RAW_LONG OTL_MAP_SQL_GUID_TO_CHAR OTL_MAP_SQL_BINARY_TO_CHAR | |||||||||||||||
16 | raw_long | ORACLE 7、8、9、10、11:RAW LONGRAW; ODBC:SQL_LONGVARBINARY,SQL_VARBINARY DB2 CLI:BLOB | |||||||||||||||
17 | refcur | 对ORACLE的8、9、10、11来说,当一个存储过程返回一个游标的时候,一个游标的占位符必须定义在SQL块中。 示例如下: "begin " | |||||||||||||||
18 | short | 16位有符号整型 | |||||||||||||||
19 | timestamp |
它需要otl_datetime类协助处理。 | |||||||||||||||
20 | tz_timestamp | 对ORACLE 9i里面的带有时区的TIMESTAMP类型。 必须定义OTL_ORA_TIMESTAMP宏,使用otl_datetime类。 | |||||||||||||||
21 | unsigned | 32位无符号整型 | |||||||||||||||
22 | varchar_long | ORACLE 7/8/9里的LONG; ODBC里的SQL_LONGVARCHAR; DB2里的CLOB |
varchar_long,raw_long clob和blob需要otl_long_string类作为数据容器。otl_connect类里的set_max_long_size()函数能设置最大长度。详细请见otl_connect类。
下面三个词用来说明对SQL语句或SQL语句块或存储过程里面表明变量的输入与输出属性。
in – input variable
out – output variable
inout – in/out variable
例1 (ORACLE)
BEGIN
:rc<int,out> := my_func(:salary<float,in>,
:ID<int,inout>,
:name<char[32],out>
);
END;
例 2(ODBC 或DB2 CLI)
New (OTL 4.0/ODBC, OTL 4.0/DB2-CLI) style
{
call :rc<int,out> := my_func(:salary<float,in>,
:ID<int,inout>,
:name<char[32],out>
)
}
Old (OTL 2.0/ODBC) style:
{
call :1<int,out> := my_func(:2<float,in>,
:3<int,inout>,
:4<char[32],out>
)
}
在绑定变量的时候,括号与类型之间是不能有空格的。如果有空格会报错。例如以下两个例子会报错:
例1:
insert into tab1 values(:salary< double >, :name< char [ 32 ] > , :emp_id< int>);
例2:
:rc< int, out > := ...;
在SQL语句中嵌入冒号
infomix的CLI能够组合OTL/ODBC实现。informix的SQL语句里面能够把冒号当作SQL语句的一部分,因此为了增加对冒号当作SQL语句的一部分的支持,OTL里面使用“\\:”来转义冒号。
在SELECT输出中明确绑定变量
OTL在解析了SELECT语句以后,就动态的识别字段的名字、类型和长度。OTL把这些数据类型与C++的数据类型关联的时候采用的是默认的关联方式。我们可以通过调用otl_stream::set_column_type()和otl_stream::set_all_column_type()函数来更改这种默认的类型关联。不过相比在SQL语句中明确绑定变量的类型来说,它并不是很准确。在SELECT语句中明确绑定变量格式如::#N<datatype>。这里的N指的是SELECT的时候字段的相对位置。因为数据库并不能解析这种格式的绑定变量,所以在SQL语句传给数据库API前,必须把这种格式的绑定变量处理掉。如:
SELECT F1:#1<SHORT>,F2 FROM TABLE;
处理后的结果如下:
SELECT F1,F2 FROM TABLE;
这种情况下的数据类型仅支持如下:
char<xxx>/double/float/int/bigint/unsigned/short/long/raw<xxx>/raw_long/timestamp/varchar_long
当然实际代码中对以上数据类型的支持还得看具体的数据库,详细的信息请参考具体数据库手册或者更方便的直接看代码有无报错。
OTL里面默认的数据类型对绝大多数的程序来说都是可用的,只有少数的情况会出错需要人工明确类型。
在4.0.117及以上版本里面,对于ORACLE的游标和ODBC/DB2 CLI的结果集,以上的明确绑定变量同样也适用。
明确输出变量替代默认方案是可选的,如果明确后没有覆盖,则还是会使用原来默认的类型关联。
声明PLSQL的表
对于OCI从OTL3.0版本开始,OTL开始支持otl_stream里面带有表,通过PL/SQL表容器实现。这个特性仅是针对SQL块或存储过程。例如,在一个存储过程里面,表名作为参数,被作为一个SQL块调用的时候,OTL能够写入或读取流里面的表名。这个技术在OCI或PROC里面是一个比较常用的,只是用接口实现稍有复杂。
在OTL4.0及以后版本里面,表名可以作为输入/输出/输入输出参数。例如:
BEGIN
my_pkg.my_proc(:salary<float,in[100]>,
:ID<int,inout[200]>,
:name<char[32],out[150]>
);
END;
上面的示例中,salary是一个最大为100位的输入参数,ID是最大为200位的输入输出参数,name是150位的输出参数。
因为存储过程是不能直接放置在代码里面的,所以上面的示例中的otl_stream大小必须设置为1。但是上面的参数并不是标量,而是预先定义好了的矢量。
从OTL4.0.115及以后版本,表的最大长度已经不再局限于32767。但是为了限制表的最大长度,仍可以通过定义OTL_STREAM_LEGACY_BUFFER_SIZE_TYPE宏来实现。
更详细的实现请见例:49/50/51/52
为ORACLE声明绑定变量的替代方法
OTL4.0.209及以上版本可以通过替代的绑定变量来同时支持ORACLE的SQL工具和OTL。这里“同时支持”意思指的是同一个SQL语句即可以通过OTL来调用,也可以通过SQL工具运行,所有的OTL的绑定变量这里都被定义为注释。如下:
INSERT INTO TABLE VALUES ( :F1,:F2);
一般都会把原来的绑定占位符进行如上例中的替换方法进行替换(变量与括号之间仍不能有空格)。这规则的目的是为了能为OTL提供一个轻量级的SQL解析器。对于SELECT语句,该功能也可以支持,只不过在SELECT里面是把空格换成注释。如下:
原来的:
SELECT F1, #1<INT>,F2 :#2<INT> FROM TABLE
替换后的:
SELECT F2,,F2 FROM TABLE;
上面这样替换后的SQL语句就可以直接传送给SQL工具执行啦,并且还支持“EXPLAIN PLAN”分析。
otl_connect
这个类封装了连接的功能,如连接、断开连接、提交、回滚等。otl_connect也就是一个用来创建连接对象并进行管理的类。
序号 | 方法、变量 | 说明 | ||||||||||||||||||
1 | int connected | 数据库是否已经连接的标志。 该标志只是在数据库连接成功后才标志为1(成功)。 如果一个已经连接成功数据库的连接在长时间没有数据库操作的情况下,由数据库主动断开了连接,该标志不会改为0,还是为1(真)。所以为了保证该标志一直有效,需要为该标志建一个“心跳”,以判断数据库是否仍旧连接为真。 如发送一个简单的SELECT CURRENT TIME FROM DUAL的请求。 | ||||||||||||||||||
2 | static int otl_initialize(const int threaded_mode = 0) | 用于初始化OTL连接库的环境的静态函数。 它仅需要在程序首次连接数据库之前调用一次即可。threaded_mode参数是为了表明是否在多线程的环境下运行。但是OTL并不保证线程安全,因为OTL里面不提供任何的线程锁或临界区。 threaded_mode = 1:多线程 threaded_mode = 0:单线程 | ||||||||||||||||||
3 | static int otl_terminate(void) | 用于中止ORACLE OCI8、9的数据库环境。 它需要在程序最后连接数据库连接后被执行一次。 该函数仅是对OCITerminate()函数的一个简单封装。 在多线程环境里面,为了能够把主线程从数据库断开,该函数必须被调用,因为它会释放一些客户端并且处理其他的一些事情。 | ||||||||||||||||||
4 | void cancel(void) | 仅用于OCI8/9/10/11版本。 用于中断SQL语句的执行。 或者说从一个线程里面异步的中断一个正在执行中的线程。 对于被中止的线程中将会返回一个“user requested cancel the current operation”异常。 | ||||||||||||||||||
5 | void change_password(…)
| 仅用于OCI8/9/10/11版本。 更改ORACLE用户的密码。 程序必须在连接在ORACLE服务端的时候被调用。 | ||||||||||||||||||
6 | void set_transaction_isolation_level(const long int level) | 仅用于DB2 CLI和ODBC。 设置事务的隔离级别。 该方法允许用户设置事务为:读提交、读未提交、可重复读、可串行化。 更多的事务隔离请见数据库手册。 OTL为事务级别定义了如下常变量 otl_tran_read_uncommied otl_tran_read_commited otl_tran_repetable_read otl_tran_serializable | ||||||||||||||||||
7 | void set_max_long_size(const int amax_size) | 为大对象设置最大的缓冲区大小。 如:varchar_long/raw_long/clob/blob对象。 该函数仅用于扩大缓冲区大小的时候使用。 默认的大小为:32767. | ||||||||||||||||||
8 | int get_max_long_size(void) | 取得大对象的缓冲区大小。 | ||||||||||||||||||
9 | void set_cursor_type(const int acursor_type = 0) | 该函数仅用于DB2 CLI和ODBC,但也可以对OCI有些影响。 一旦设置好了某个类型后,通过该连接的所有的otl_stream流的SQL操作都会被影响。 支持的游标类型如下(详细的请见ODBC或DB2 CLI手册): SQL_CURSOR_FORWARD_ONLY(DEFAULT SETTING) SQL_CURSOR_STATIC SQL_CURSOR_KEYSET_DRIVEN SQL_CURSOR_DYNAMIC | ||||||||||||||||||
10 | void set_timeout(const int atimeout = 0) | 仅适用于ODBC,对OCI或DB2 CLI没有作用。 用于设置连接的超时时间,一旦设置后,通过该连接的所有的SQL语句都将受影响。 单位为秒。 在OCI里面也可以通过另外一种方式实现该功能,如通过一个线程进行SQL操作,另一个线程作计时,如果时间到了,SQL还未执行完成,则调用calcel()函数强制中断。 在DB2 CLI里面类似上面的方式也可以用,只是把otl_connect::cancel()换成otl_stram::cancel()即可。 在将来,如果OCI或DB2 CLI支持该功能,那么该函数将会被复用。 | ||||||||||||||||||
11 | otl_connect(const char * connect_str,const int auto_commit = 0) | 构造函数。 创建一个OTL连接对象,并调用rlogon()函数。 | ||||||||||||||||||
12 | void rlogon(…)
| 连接数据库。
对于OCI、ODBC和DB2 CLI都有不同格式的连接串。 OCI: USERNAME/PASSWORD(对本地数据库) USERNAME/PASSWORD@TNS_NAME(远程数据库通过SQL*NET)
ODBC和DB2 CLI USER/PASSWORD@DSN(类ORACLE格式) DSN=VALUE;UID=VALUE;PWD=VALUED(ODBC格式)
在某些情况下,密码还可能包括有@符号,如果需要增加该符号,则需要通过”\”标志进行转义。 auto_commit标志是用来设置连接的自动提交标志。它意味着,每执行一个SQL语句,都将会自动提交该事务。但是与otl_stream里面的自动提交是两码事。 如果需要设置自动提交,则将该参数设置为1,否则默认为0(不自动提交)。 在ORACLE7、ODBC或DB2 CLI版本里面,自动提交意味着每执行完都提交,但是在ORACLE8及以后版本里面,该标志则是执行成功后才提交。 | ||||||||||||||||||
13 | void rlogon(Lda_Def * lda) | 连接到某个第过第三方库或嵌入式SQL连接的数据库里面。 该函数仅用于OCI7。 详细请见例:58 | ||||||||||||||||||
14 | void rlogon(…)
| 通过其他的ODBC或第三方库连接数据库。 它仅用于ODBC或DB2 CLI。 | ||||||||||||||||||
15 | void rlogon(…)
| 仅用于ODBC或DB2 CLI。 必须定义OTL_UNICODE_EXCEPTION_AND_RLOGON宏。 连接数据库。 该函数在定义了UNICODE情况下使用,它能够通过UNICODE的用户名和密码连接数据库。 | ||||||||||||||||||
16 | otl_connect(…)
| 仅适用于ODBC或DB2 CLI。 通过ODBC或第三方库进行数据库连接。 | ||||||||||||||||||
17 | void rlogon(…)
| 仅适用于OCI8i/9i/10g/11g。 通过PRO*C或第三方库连接数据库。 它必须在定义了OTL_ORA8_PROC宏的情况下使用。 | ||||||||||||||||||
18 | void rlogon(…)
| 仅适用于OCI 8/8i/9i/10g/11g。 连接数据库,并且设置XA库需要的的外部和内部连接名。 | ||||||||||||||||||
19 | void logoff() | 断开数据库连接。 如果OTL是通过PRO*C或第三方库连接的数据库,则么该函数只是断开与PRO*C的关系,而不是实际上断开数据库连接。 | ||||||||||||||||||
20 | void server_attach(…)
| 仅适用于OCI 8/8i/9i/10g/11g。 该函数为对ServerAttach()函数的封装。 主要功能是开始一个session,结合session_begin()和sessin_end()使用。 主的优点在于相比于传统的连接池,性能更佳。tnsname主要是用来连接远程服务器的,对于本地服务默认可以设置为0。 | ||||||||||||||||||
21 | void server_detach() | 仅适用于OCI8/8i/9i/10g/11g。 断开ORACLE连接。 | ||||||||||||||||||
22 | void session_begin(…)
| 仅适用于OCI 8/8i/9i/10g/11g。 开始一段数据库的SESSION,主要功能在于通过attach/detach函数来开始一个SESSION。 主要的目的在于通过SESSION来执行一系列的函数比传统的连接池执行起来性能上要快不少。 | ||||||||||||||||||
23 | void session_end() | 仅适用于OCI 8/8i/9i/10g/11g。 结束一个ORACLE的SESSION | ||||||||||||||||||
24 | void session_reopen(…)
| 仅适用于OCI 8/8i/9i/10g/11g。 重新打开一个已经被session_end()关闭过的session。 重新打开一个已经关闭过的session的优点在于,重新打开速度上要快5-10%。 因为用户名和密码在前面的session_begin()里面已经初始化过,所以不需要重新再处理。 详细请见例:61 | ||||||||||||||||||
25 | void commit() | 提交一个事务。 对于ORACLE/ODBC/DB2 CLI来说,默认的自动提交为否,那么对于所有执行过的事务都需要手工的调用该函数进行事务提交。 如果设置了自动提交,则不需要再调用该函数。 | ||||||||||||||||||
26 | void commit_nowait() | 在定义了宏OTL_ORA10_R2或OTL_ORA11G宏下有用。 异步提交。 仅适用于ORACLE10.2及以后版本。 | ||||||||||||||||||
27 | void rollback() | 回滚当前事务。 | ||||||||||||||||||
28 | void auto_commit_off() void auto_commit_on() | 设置自动提交为开或关。 对连接或SESSION都有效。 注:该函数仅部分的向后兼容。 | ||||||||||||||||||
29 | void set_stream_pool_size (const int max_size = otl_max_default_pool_size) | 设置otl_stream的缓冲区大小。 使用该函数必须定义OTL_STREAM_POOLING_ON、OTL_STL或OTL_ACE宏。 如果OTL_STREAM_POOLING_ON宏定义了,该函数体才被包含进代码里面。 同时,一个默认的流缓冲区将被作为otl_connce一部分自动分配。 然后如果调用了这个函数,那么先前分配的将会被释放,然后进行重新分配。 | ||||||||||||||||||
30 | void set_character_set (const int char_set = SQLCS_IMPLICIT) | 仅适用于定义了OTL_UNICODE宏的ORACLE OCI8i/9i/10g/11g环境。 SQLCS_IMPLICIT:数据库默认的字符集 SQLCS_NCHAR:数据库国际字符集 当使用了VARCHAR2/CHAR/LONG/CLOB类型的时候,则需要默认的字符集; 当使用了NVARCHAR2/NCHAR/NCLOB字段类型的情况下,则需要设置为国际字符集。 SQLCS_IMPLICIT/SQLCS_NCHAR是在ORACLE的OCI头文件里面被定义的。
一旦该函数设置了字符集,那么所有的通过该函数设置过的otl_connect连接的流都将使用该字符集。 在使用了UNICODE后,字符的定义也将被一同进行了扩展。 如CHAR[20]代表的是容纳一个双字节的19个字符,还加上两个字节的空字符。 这样做的主要目的是为了跟数据库里面兼容。 | ||||||||||||||||||
31 | void set_throw_on_sql_success_with_info (const bool throw_flag = false) | 仅适用于ODBC和DB2 CLI。 必须定义宏OTL_THROW_ON_SQL_SUCCESS_WITH_INFO。 在定义了该标志为真为,对于执行SQLExecDirect()/SQLExecute()函数成功后,仍抛出一个异常。 这对某些需要获取更多信息的执行非常有帮助,如调用一个存储过程。 | ||||||||||||||||||
32 | otl_connect & operator<<(const char * str) | 往otl_connect对象写入一个字符串。 如果该对象未连接至数据库,那么该字符串将被作为连接的用户名密码格式被otl_connect对象用来连接数据库; 如果已经连接成功数据库,则该字符串将被作为SQL语句立刻被执行。 | ||||||||||||||||||
33 | otl_connect & operator<<=(const char *str) | 往otl_connect对象写入字符串,该字符串其实就是一个将要被otl_stream执行的SQL语句。 | ||||||||||||||||||
34 | otl_connect & operator>>(otl_stream & s) | 把通过otl_connect<<=()传进来的SQL语句交给otl_stream执行。 如果没有传入的SQL语句,那么将会抛出一个“***INVALID COMAND ***”异常。 | ||||||||||||||||||
35 | long direct_exec(…)
| 执行一段不带占位符的SQL语句,返回该语句执行的记录数。 该函数返回下面两种情况的返回值: -1:如果异常被关闭了,但是数据库API返回一个错误。 >=0:如果SQL执行成功。 | ||||||||||||||||||
36 | void syntax_check (const char * sqlstm); | 检查SQL语句,如果有错误则会抛出一个异常。 | ||||||||||||||||||
37 | void set_connection_mode (const int connection_mode) | 在定义了OTL_ODBC_MULTI_MODE宏的情况下,OTL可以通过不用定义相关数据为的宏,而通过ODBC进行多种数据库连接。 它必须在数据库连接之前进行调用。 下面这些OTL定义的常量为OTL支持的数据库连接类型。 OTL_DEFAULT_ODBC_CONNECT:等同于设置了OTL_ODBC宏。 下面的这些数据库都可以进行连接DB2/FIREBIRD/INFORMIX/MS ACCESS/ORACLE/SAP/MAXDB/SQLITE/SYBASE/其它兼容ODBC数据库的数据库。 OTL_TIMESTEN_ODBC_CONNECT: OTL_MSSQL_2005_ODBC_CONNECT: OTL_POSTGRESQL_ODBC_CONNECT: OTL_ENTERPRISE_DB_ODBC_CONNECT: OTL_MYODBC35_ODBC_CONNECT: OTL_MSSQL_2008_ODBC_CONNECT: | ||||||||||||||||||
38 | int get_connection_mode() | 仅在定义了OTL_ODBC_MULTI_MODE宏情况下适用。 取得数据库连接类型。 | ||||||||||||||||||
39 | void set_prog_name(const char * prog_name) | 仅适用于OTL_DB2_CLI宏定义了的情况下。 设置程序的名称,该名称是在数据库“list application”命令调用时候显示的名称。 它必须在连接之前调用。 如下: otl_connect db; db.set_prog_name(“myapp”); db.rlogon(“usr/pass@db”); |
otl_exception
这个类是OTL用来抛出异常的类。如果数据库API返回一个非0的错误值,则OTL会将会抛出一个otl_exception的异常。一个otl_exception异常有可能是一个数据库错误或是一个OTL定义的错误。
序号 | 函数、成员变量 | 说明 |
1 | char stm_text[2048 or OTL_EXCEPTION_STM_TEXT_SIZE] | OTL异常里面SQL语句的前2047个字符。 当设置了stream label(在otl_stream或open()函数里面的sqlstm_label设置)后,它就被SQL的数据成员替代了SQL语句。 |
2 | char var_info[256] | 如果抛出了“Incompatible data types in stream operation”异常,则该变量被用来填充绑定变量和字段信息。 如:bind variable name/select output column number <datatype> |
3 | #if defined(OTL_UNICODE_EXCEPTION_AND_RLOGON) SQLWCHAR msg[1000]; #else unsigned char msg[1000]; #endif | 数据库错误信息或是OTL错误信息。 |
4 | int code | 数据库错误的编码或是OTL错误编码 |
5 | #if defined(OTL_UNICODE_EXCEPTION_AND_RLOGON) SQLWCHAR sqlstate[1000]; #else unsigned char sqlstate[1000]; #endif | 仅适用于ODBC或DB2 CLI。 对于OCI它始终为空。 用来存放SQL的状态信息,详细请见ODBC或DB2 CLI手册。 |
6 | #if defined(OTL_EXTENED_EXCEPTION) #if defined(OTL_UNICODE_EXCEPTION_AND_RLOGON) int arr_len; SQLWCHAR *msg_arr[]; SQLWCHAR *sqlstate_arr[]; int code_arr[] #else int arr_len; char * msg_arr[]; char * sqlstate_arr[]; int code_arr[]; #endif #endif | 扩展字段信息。 通过SQLGetDiagRec()函数,获取所有的ODBC/DB2 CLI动态记录信息。 OTL的异常往往只取第一条信息,但对于ODBC、DB2 CLI在某些情况下,它会带有多条动态的信息,此时该变量里面包含有所有的信息。 arr_len是信息数量。 msg_arr里面是消息; sqlstate_arr里面是sqlstate; code_arr里面是错误码。 |
7 | #if defined(OTL_EXCEPTION_ENABLE_ERROR_OFFSET) int error_offset #endif | 仅适用于OCI。 SQL语句解析错误码。 |
8 | enum { disabled = 0, enabled = 1 }; | 定义两个常量用于静态的SQL语句。 |
otl_long_string/olt_long_unicode_string
这两个类主要用来处理大对象数据。从OTL4.0版本开始,otl_long_string还可以处理任何类型的RAW/BIANRY类型。下面列出了常见数据库的一些大对象类型:
- Oracle 7: LONG, RAW, LONG RAW
- Oracle 8, 8i, 9i, 10g, 11g: LONG, RAW, LONG RAW; CLOB, BLOB
- MS SQL Server: TEXT, IMAGE, VARBINARY, BINARY, VARCHAR(MAX), VARBINARY(MAX)
- DB2: CLOB, BLOB
- Sybase: TEXT, IMAGE, VARBINARY, BINARY
- PostgreSQL: TEXT, BYTEA,
- SAP/MAX DB: CHAR() BYTE, VARCHAR() BYTE, LONG VARCHAR, LONG VARCHAR BYTE
- MySQL: LONGTEXT, LONGBLOB, VARBINARY, BINARY
otl_long_unicode_string是用来处理UNICODE字符的大对象类型,它可以处理下面这些类型:
- Oracle 8i, 9i, 10g: LONG, CLOB; the database default character set may be set to ASCII, or UTF-8, etc
- Oracle 8i, 9i, 10g: NCLOB; the database national character set may be set to whatever is allowed for a concrete version of the database (8i and 9i/10g differ / are not the same in that regard, as far as supporting different versions of Unicode, and what sets are allowed for national character data types)
- MS SQL NTEXT
- DB2 CLOB / DBCLOB when the database supports Unicode (UTF-8, UCS-2, etc.)
如果定义了OTL_UNICODE宏,那么对于ORACLE的LONG RAWS/BLOB,MS SQL IMAGES,DB2 BLOBS等仍要通过otl_long_string来处理。因为他们仍然是大对象。
OTL还定义了下列类型用于处理LOBS类型。
- varchar_long for Oracle 7/8/8i/9i/10g LONG, MS SQL Server/Sybase TEXT/NTEXT, DB2 CLOB/DBCLOB
- raw_long for Oracle 7/8/8i/9i/10g RAW, LONG RAW, MS SQL Server/Sybase IMAGE, DB2 BLOB
- clob for Oracle 8/8i/9i/10g CLOB, NCLOB (if #define OTL_UNICODE is enabled).
- blob for Oracle 8/8i/9i/10g BLOB
大对象和NULL值
大对象和NULL值的操作,与其他类型的字段有很大的区别。对于大对象与NULL的处理方式分为下面两种情况:
一、Oracle 7/8/8i/9i/10g's LONG, Oracle 7/8's LONG RAW, MS SQL Server/Sybase's TEXT, MS SQL Server/Sybase's IMAGE, DB2's CLOB/BLOB:
相对于一般的数据库类型,以上这些大对象可以通过两种方式设置为空。一是往流里面写入一个otl_null()值;二是通过调用otl_long_string::set_len(0)把大对象值设置为0.
对于输出,也有两种方式用来检测是否为空。一是通过is_null()进行判断;二是通过otl_long_string::len()获取结果后与0进行比较。
二、Oracle 8/8i/9i/10g's CLOB, Oracle 8/8i/9i/10g's BLOB:
对于以上的数据库类型,对于大对象空值的判断,在输入参数上,与上面的是同样的具有两川方式处理。但是对于输出参数的处理上,则只能通过otl_long_string::len()返回值与0进行比较。所以推荐使用otl_long_string::len()操作来判断空值。
下面分别介绍一个otl_long_string类和otl_long_unicode_string类。
otl_long_string
序号 | 函数、成员变量 | 说明 | ||||||||||||
1 | unsigned char * v; | 指向LOB值的指针。 | ||||||||||||
2 | otl_long_string(…)
| 构造函数。 创建一个otl_long_string的实例。 主要是分配内存,并设置内部变量。 为了保证能分配到正确的大小,otl_connect::set_max_long_size()必须声明的大于或等于otl_long_string的缓冲区大小。 | ||||||||||||
3 | otl_long_string(…)
| 构造函数。 该函数通过定义一个指针指向外部的一个缓冲区来替代默认的缓冲区。 同时原来的缓冲区不再分配空间。 | ||||||||||||
4 | void set_len(const int len = 0) | 动态的设置缓冲区大小。 它必须在写LOB值之前调用。 | ||||||||||||
5 | void set_last_piece(const bool last_piece = false) | 仅对OCI8i/9i/10g/11g有效。 对于ODBC和DB2 CLI不起作用。 当otl_long_string与otl_lob_stream同时使用的时候,该函数表明otl_string_string是写入otl_stream里面的最后一个序列。 | ||||||||||||
6 | int len() | 返回缓冲区的大小。 | ||||||||||||
7 | unsigned char & operator[](int ndx) | 读取LOB里面非法的字节。 | ||||||||||||
8 | otl_long_string & operator =(const otl_long_string&) | 赋值构造函数 | ||||||||||||
9 | otl_long_string(const otl_long_string&) | 拷贝构造函数 |
otl_long_unicode_string
序号 | 函数、成员变量 | 说明 | ||||||||||||
1 | otl_long_unicode_string(…)
| 构造函数。 创建一个otl_long_unicode_string的实例。 主要是分配内存,并设置内部变量。 为了保证能分配到正确的大小,otl_connect::set_max_long_size()必须声明的大于或等于otl_long_string的缓冲区大小。 | ||||||||||||
2 | otl_long_unicode_string(…)
| 构造函数。 该函数通过定义一个指针指向外部的一个缓冲区来替代默认的缓冲区。 同时原来的缓冲区不再分配空间。 | ||||||||||||
3 | void set_len(const int len = 0) | 动态的设置缓冲区大小。 它必须在写LOB值之前调用。 | ||||||||||||
4 | int len(void) | 返回缓冲区的大小。 | ||||||||||||
5 | unsigned short & operator[](int ndx) | 读取LOB里面非法的字节。 | ||||||||||||
6 | otl_long_unicode_string & operator =(const otl_long_unicode_string) | 赋值构造函数 | ||||||||||||
7 | otl_long_unicode_string (const otl_long_unicode_string&) | 拷贝构造函数 |
常量的SQL语句
一个没有绑定变量的SQL语句、SQL语句块或是存储过程就被称为常量的SQL语句。OTL通过一个静态的函数来执行这样的SQL语句。
例如:
// static otl_cursor::direct_exec()
otl_cursor::direct_exec
(
db, // connect object
"create table test_tab(f1 int, f2 varchar(30))" // create table
);
otl_cursor::direct_exec
(
db, // connect object
"drop table test_tab", // SQL statement or PL/SQL block
otl_exception::disabled // disable OTL exceptions,
// in other words, ignore any
// database error
); // drop table
// or otl_connect::direct_exec()
db.direct_exec // connect object
(
"create table test_tab(f1 int, f2 varchar(30))" // create table
);
db.direct_exec // connect object
(
"drop table test_tab", // SQL statement or PL/SQL block
otl_exception::disabled // disable OTL exceptions,
// in other words, ignore any
// database error
); // drop table
// or otl_connect::operator<<(const char*)
db<<"create table test_tab(f1 number, f2 varchar2(30))";
try
{
db<<"drop table test_tab""; // SQL statement or PL/SQL block
}
catch(otl_exception&)
{
// ignore a database error
}
otl_cursor是OTL的一个内部类。它是对direct_exec()函数的一个底层类。因为以后版本该类可能不再对外提供,所以不建议使用。
下面这个例子为direct_exe()返回结果值的例子:
// static otl_cursor::direct_exec
long rpc=otl_cursor::direct_exec
(
db, // connect object
"delete from test_tab where f1>=95"
);
cout<<"Rows deleted: "<<rpc<<endl;
// or otl_connect:direct_exec
long rpc=db.direct_exec // connect object
(
"delete from test_tab where f1>=95"
);
cout<<"Rows deleted: "<<rpc<<endl;
OTL的流缓冲池
一般来讲,流一般作为一个局部的变量被使用,当使用完毕后就立刻关闭,如果需要再次使用就需要再次的声明变量,如此循环。OTL流的缓冲池(内存池)是一个解决以往的流性能低下的一个机制。当流被关闭后,实际上流的相关变量被保存在一个流缓冲池里面,以便再利用。
每一个流在解析SQL或与数据库层打交道的时候都存在着巨大的资源开销。OTL通过流缓冲池机制来解决这个不必要的开销以提高性能。
当一个流“关闭”后,实际上,它被保存在一个流缓冲池里面。如果后面再需要一个类似的流,那么就只需要把流缓冲池里面的流取出来赋给相应的流变量即可再使用。不管该变量是局部还是全局的变量。相似的地方在于流的缓冲区大小与流相关的SQL语句是相同的。它们被保存在流缓冲池里面。
比如说有三个已经被关闭了的相似(缓冲区大小与SQL语句类型相同)的流已经被分配了内存资源。但实际上,在流的缓冲池里面只有一个入口,也就是说只有这三个流的一个副本。如果后面再需要相似的流,那么就会从中把取出该副本赋给对应的变量使用。如果有一个循环里面要不停的使用这个相同的流的话,那实际上流的主体总是这个相同的流。它被从流缓冲池里面取出来后赋给相应的变量再续使用。
在某些时候,某个流可能就真的只使用一次就关闭,这个时候otl_stream::close()有一个对应的扩展函数提供给开发者强制关闭流而不放在流缓冲池里面。
如果在某些情况下的确不想使用流缓冲池技术,我们还可以通过宏来关闭流缓冲池。这个需要在编译的时候确定下来。
通过上面的介绍,很明显,流缓冲池是一个otl_connect对象,同样,它还有一个最大容量限制,我们可以通过otl_connect::set_stream_pool_size()函数进行设置。
因为流缓冲池使用了map和vector,所以在使用流缓冲池的时候,必须要定义OTL_STL(或OTL_ACE)宏。
当一个新的流被要求加入到流缓冲池中,但是流缓冲池已满了,这个时候,用的最少的那个流将被从流缓冲池中清除,而把最新的这个流放进来。
从Sergei Kuchin统计的信息来看,流缓冲池还是相对有一个些开销的,这个主要原因是因为STL里面的MAP容器的开销导致。
下面为流缓冲池的一个简单图例: