1. OTL 编程简介
1.1. 功能
OTL是Oracle 和 ODBC 的模板库,它屏蔽数据库操作的底层,提供数据库连接功能,以标准 C++ 流的方式完成嵌入式 SQL 语句、存储过程的执行和光标操作。
OTL 是 Oracle, Odbcand DB2-CLI Template Library 的缩写,是一个C++编译中操控关系数据库的模板库,它目前几乎支持所有的当前各种主流数据库,例如Oracle, MS SQL Server, Sybase, Informix, MySQL, DB2, Interbase / Firebird,PostgreSQL, SQLite, SAP/DB, TimesTen, MS ACCESS等等。OTL中直接操作Oracle主要是通过Oracle提供的OCI接口进行,进行操作DB2数据库则是通过CLI接口来进行,至于MS的数据库和其它一些数据库,则OTL只提供了ODBC来操作的方式。当然Oracle和DB2也可以由OTL间接使用ODBC的方式来进行操纵。
在MS Windowsand Unix 平台下,OTL目前支持的数据库版本主要有:Oracle 7 (直接使用 OCI7), Oracle 8 (直接使用 OCI8), Oracle 8i (直接使用OCI8i), Oracle 9i (直接使用OCI9i), Oracle 10g (直接使用OCI10g), DB2 (直接使用DB2 CLI), ODBC 3.x ,ODBC 2.5。OTL最新版本为4.0,参见http://otl.sourceforge.net/,下载地址http://otl.sourceforge.net/otlv4_h.zip。
优点:
a. 跨平台
b. 运行效率高,与C语言直接调用API相当
c. 开发效率高,起码比ADO.net使用起来更简单,更简洁
d. 部署容易,不需要ADO组件,不需要.net framework 等
1.2. otl_connect 类
提供数据库连接、事务操作的功能。
(SHBOSS开发中,由 CDBConnGuard 类屏蔽之并进行连接等管理。)
主要成员函数:
² intconnected; // 是否已经连接到数据库
² static intotl_initialize(const int threaded_mode=0); // 初始化 OTL 环境,必须在调用 OTL API 之前被调用;threaded_mode=1表示运行在多线程环境
² voidset_max_long_size(const int amax_size); // 设置缓冲区大小(仅对大数据字段适用)
² otl_connect(constchar* connect_str,const int auto_commit=0); // connect_str的格式:USER/PASSWORD@TNS_ALIAS,如果是本地连接则不需要TNS_ALIAS
² void rlogon(constchar* connect_str,const int auto_commit=0);
² voidlogoff();
² void server_attach(const char* tnsname=0); // OTL/OCI8 only
² void server_detach();//OTL/OCI8 only
² session_begin(constchar* username, const char* password, const int auto_commit=0);// OTL/OCI8 only
² void session_end();//OTL/OCI8 only
² void session_reopen(constint auto_commit=0)// OTL/OCI8 only,打开用 session_end 关闭的会话
² void commit();
² void rollback();
² 注释:使用 server、session来登录比用 rlogon 效率更高
² 建议使用显式的commit 和rollback,不使用autocommit
1.3. otl_stream 类
1.3.1. 概述
以宿主调用和流的方式完成 SQL 语句的执行。
工作原理:先分析程序员指定的 SQL 语句,之后以流的方式把数据和 otl_stream 内部的缓冲区作交换,通过 flush() 将数据刷新到数据库中。
otl_nocommit_stream
1.3.2. 主要成员函数
otl_stream( const short arr_size, otl_connect& db, const char* ref_cur_placeholder=0) ) | 构造函数 arr_size表示缓冲记录的条数 sqlstm 表示要执行的 SQL 语句 db 表示使用的数据库连接 ref_cur_placeholder 表示返回的光标(如果有的话)的名字 |
void open( const short arr_size, const char* sqlstm, otl_connect& db, const char* ref_cur_placeholder=0) ) | 同上 |
void close() | 关闭流 |
int good() | 测试流是否已经成功打开 |
int eof() | 是否到了流的结尾,和标准 C++ 流的 eof 相同 |
void flush() | 刷新 otl_stream 的缓冲区(获取新的数据或者把数据写到数据库中);当缓冲区满的时候,otl_stream 会自动 flush;如果设置了自动提交,则在 flush 的时候将会触发提交 |
void clean(const int clean_up_error_flag=0) | 清空缓冲区而不执行刷新操作 |
int is_null() | 测试通过 >> 运算符获取的值是否为空 |
long get_rpc() | 获取处理了的记录数目,限于INSERT、DELETE、UPDATE语句 |
otl_column_desc* describe_select(int& desc_len); | 获取字段描述信息,适用于SELECT语句、引用光标(OCI)和存储过程(ODBC for MS SQL Server and Sybase)
class otl_column_desc{ public: char name[512]; // column name int dbtype; // database dependent, column datatype code. int otl_var_dbtype; // OTL defined, column datatype code int dbsize; // column length int scale; // for numeric columns, column scale int prec; // for numeric columns, column precision int nullok; // indicator whether column is nullable or not }; |
void set_commit( int auto_commit=0 ) | 刷新(flush)缓冲区的时候,是否自动提交事务。从更易于理解的角度,建议在显式提交的应用中用 otl_nocommit_stream。 |
1.3.3. OTL 的数据类型
otl_var_char | null terminated string (code=1) |
otl_var_double | 8 byte floating point number (code=2) |
otl_var_float | 4 byte floating point number (code=3) |
otl_var_int | 32 bit signed integer (code=4) |
otl_var_unsigned_int | 32 bit unsigned integer (code=5) |
otl_var_short | 16 bit signed integer (code=6) |
otl_var_long_int | 32 signed integer 9code=7) |
otl_var_timestamp | datatype that is mapped into TIMESTAMP_STRUCT, ODBC only (code=8) |
otl_var_varchar_long | datatype that is mapped into LONG in Oracle 7/8, TEXT in MS SQL Server and Sybase (code=9) |
otl_var_raw_long | datatype that is mapped into LONG RAW in Oracle 7/8, IMAGE in MS SQL Server ad Sybase (code=10) |
otl_var_clob | datatype that is mapped into CLOB in Oracle 8 (code=11) |
otl_var_blob | datatype that is mapped into BLOB in Oracle 8 (code=12) |
1.3.4. 示例
otl_stream& operator>>(char& c); otl_stream& operator>>(unsigned char& c); otl_stream& operator>>(char* s); otl_stream& operator>>(unsigned char* s); otl_stream& operator>>(int& n); otl_stream& operator>>(unsigned& u); otl_stream& operator>>(short& sh); otl_stream& operator>>(long int& l); otl_stream& operator>>(float& f); otl_stream& operator>>(double& d); otl_stream& operator>>(otl_long_string& s); // read the LOB from the stream otl_stream& operator>>(TIMESTAMP_STRUCT& s); // read the timestamp from the stream // (OTL 3.1/ODBC only) otl_stream& operator>>(otl_datetime& dt); // read date/time info from the stream otl_stream& operator>>(otl_XXX_tab<…>& tab); // read PL/SQL tables from the stream (OCIx)
otl_stream& operator>>(otl_lob_stream& lob); // read reference to CLOB/BLOB from otl_stream // into otl_lob_stream (OCI8). In other words, // initialize otl_lob_stream for reading CLOB/BLOB // in stream mode
|
otl_stream& operator<<(const char c); otl_stream& operator<<(const unsigned char c); otl_stream& operator<<(const char* s); otl_stream& operator<<(const unsigned char* s); otl_stream& operator<<(const int n); otl_stream& operator<<(const unsigned u); otl_stream& operator<<(const short sh); otl_stream& operator<<(const long int l); otl_stream& operator<<(const float f); otl_stream& operator<<(const double d); otl_stream& operator<<(const otl_null n); // write NULL into the stream otl_stream& operator<<(const otl_long_string& d); // write the LOB into the stream otl_stream& operator<<(const TIMESTAMP_STRUCT& d); // write the timestamp into the stream // (OTL 3.1/ODBC only) otl_stream& operator<<(const otl_datetime& dt); // write date/time info into the stream otl_stream& operator<<(const otl_XXX_tab& tab); // write PL/SQL tables into the stream (OCIx) otl_stream& operator<<(otl_lob_stream& lob); // write otl_lob_stream descriptor intoto otl_stream (OCI8). // In other words, initialize otl_lob_stream // for writing CLOB/BLOB in stream mode.
|
1.4. 错误处理(otl_exception)
classotl_exception {
public:
char stm_text[2048]; // 导致异常的SQL 语句
char var_info[256]; // 导致数据类型不兼容的邦定变量的名字
unsigned char msg[1000]; // 数据库或者OTL的错误信息
int code; // 错误代码
};
1.5. 其它
1.5.1. 使用邦定变量
示例:
INSERT INTO my_table VALUES(
:employee_id<int>,
:supervisor_name<char[32]>)
placeholder(比如employee_id)可以用没有意义的f1代替,但是在一个SQL语句中不能使用相同名字的placeholder。
这里,支持的数据类型有:
int | signed int |
unsigned | unsigned int |
short | short int |
long | long int |
float | byte floating point number |
double | byte floating point number |
timestamp | MS SQL Server/Sybase DATETIME, Oracle DATE; requires TIMESTAMP_STRUCT (OTL/ODBC), or otl_datetime (both ODBC and OCIx) |
char[length] | null terminated string; length is database dependent; for Oracle in [3,32545]; for ODBC it depends on the database backend and the ODBC driver |
varchar_long | for Oracle 7: LONG; for Oracle 8: LONG; for ODBC: SQL_LONGVARCHAR |
raw_long | for Oracle 7: LONG RAW; for Oracle 8: LONG RAW; for ODBC: SQL_LONGVARBINARY |
clob | for Oracle 8: CLOB |
blob | for Oracle 8; BLOB |
1.5.2. char 字段
在执行INSERT语句的时候,如果数据库中char字段的大小是n,则这个INSERT语句的邦定变量的大小要为n+1;否则当邦定变量的大小为n时,执行INSERT会出错。
例如:
INSERT INTO my_table VALUES(
:1<int>,:2<char[33]>,:3<double>,:4<char[129]>
)
这个例子中,my_table的第二和第四个字段的大小分别为32和128。
1.5.3. number 字段
对数据库中定义的数字字段,可以根据字段的大小使用16位、32 位的整数和double类型;当然,如果对所有OCI的数字字段使用double,也不会出错。
1.5.4. otl_datetime
classotl_datetime{
public:
int year;
int months;
int day;
int hour;
int minute;
int second;
};
1.5.5. otl_null
otl_null表示一个空值,当要INSERT一个空值到数据库中时,必须使用它。
otl_null的定义如下:
class otl_null{
public:
otl_null(){}
~otl_null(){}
};
1.6. 示例: insert&select
#include <iostream.h> #include <stdio.h>
#define OTL_ORA8 // Compile OTL 3.1/OCI8 #include <otlv31.h> // include the OTL 3.1 header file
otl_connect db; // connect object
void insert() // insert rows into table { otl_stream o(50, // buffer size "insert into test_tab values(:f1<float>,:f2<char[31]>)", // SQL statement db // connect object ); char tmp[32];
for(int i=1;i<=100;++i){ sprintf(tmp,"Name%d",i); o<<(float)i<<tmp; } }
void select() { otl_stream i(50, // buffer size "select * from test_tab where f1>=:f<int> and f1<=:f*2", // SELECT statement db // connect object ); // create select stream
float f1; char f2[31];
i<<8; // assigning :f = 8 // SELECT automatically executes when all input variables are // assigned. First portion of output rows is fetched to the buffer
while(!i.eof()){ // while not end-of-data i>>f1>>f2; cout<<"f1="<<f1<<", f2="<<f2<<endl; }
i<<4; // assigning :f = 4 // SELECT automatically executes when all input variables are // assigned. First portion of output rows is fetched to the buffer
while(!i.eof()){ // while not end-of-data i>>f1>>f2; cout<<"f1="<<f1<<", f2="<<f2<<endl; }
}
int main() { otl_connect::otl_initialize(); // initialize OCI environment try{
db.rlogon("scott/tiger"); // connect to Oracle
otl_cursor::direct_exec ( db, "drop table test_tab", otl_exception::disabled // disable OTL exceptions ); // drop table
otl_cursor::direct_exec ( db, "create table test_tab(f1 number, f2 varchar2(30))" ); // create table
insert(); // insert records into table select(); // select records from table
}
catch(otl_exception& p){ // intercept OTL exceptions cerr<<p.msg<<endl; // print out error message cerr<<p.stm_text<<endl; // print out SQL that caused the error cerr<<p.var_info<<endl; // print out the variable that caused the error }
db.logoff(); // disconnect from Oracle
return 0;
}
Output
f1=8, f2=Name8 f1=9, f2=Name9 f1=10, f2=Name10 f1=11, f2=Name11 f1=12, f2=Name12 f1=13, f2=Name13 f1=14, f2=Name14 f1=15, f2=Name15 f1=16, f2=Name16 f1=4, f2=Name4 f1=5, f2=Name5 f1=6, f2=Name6 f1=7, f2=Name7 f1=8, f2=Name8
|
1.7. 参考文档
《otl3.doc》
《Otl说明.doc》